cloki
Version:
LogQL API with Clickhouse Backend
163 lines (150 loc) • 4.58 kB
JavaScript
const { hasExtraLabels, hasStream, addStream } = require('../common')
const Sql = require('@cloki/clickhouse-sql')
/**
*
* @param token {Token}
* @param query {Select}
* @param index {string}
* @returns {Select}
*/
const genericReq = (token, query, index) => {
if (token.Child('number_value').Child('duration_value') ||
token.Child('number_value').Child('bytes_value')) {
throw new Error('Not implemented')
}
const label = token.Child('label').value
const val = parseInt(token.Child('number_value').value)
if (isNaN(val)) {
throw new Error(token.Child('number_value').value + 'is not a number')
}
if (hasStream(query)) {
return addStream(query, (s) => s.filter(module.exports.streamWhere[index](label, val)))
}
if (hasExtraLabels(query)) {
return query.where(module.exports.extraLabelsWhere[index](label, val))
}
return query.where(module.exports.simpleWhere[index](label, val))
}
/**
*
* @param label {string}
* @param val {string}
* @param sign {Function}
* @returns {Conditions}
*/
const genericSimpleLabelSearch =
(label, val, sign) => Sql.And(
Sql.Eq(new Sql.Raw(`JSONHas(labels, '${label}')`), 1),
sign(new Sql.Raw(`toFloat64OrNull(JSONExtractString(labels, '${label}'))`), val)
)
/**
*
* @param lbl {string}
* @param val {string}
* @param sign {Function}
* @returns {Conditions}
*/
const genericExtraLabelSearch =
(lbl, val, sign) => Sql.Or(
Sql.Ne(new Sql.Raw(
`arrayExists(x -> x.1 == '${lbl}' AND (coalesce(` +
sign(new Sql.Raw('toFloat64OrNull(x.2)'), val).toString() + ', 0)), extra_labels)'
), 0),
Sql.And(
Sql.Eq(new Sql.Raw(`arrayExists(x -> x.1 == '${lbl}', extra_labels)`), 0),
Sql.Eq(new Sql.Raw(`arrayExists(x -> x.1 == '${lbl}', labels)`), 1),
sign(new Sql.Raw(`toFloat64OrNull(arrayFirst(x -> x.1 == '${lbl}', labels).2)`), val)
)
)
const genericStreamSearch = (label, fn) =>
(e) => {
if (!e || e.EOF) {
return true
}
if (!e || !e.labels || !e.labels[label]) {
return false
}
const val = parseFloat(e.labels[label])
if (isNaN(val)) {
return false
}
return fn(val)
}
module.exports.simpleWhere = {
eq: (label, val) => genericSimpleLabelSearch(label, val, Sql.Eq),
neq: (label, val) => genericSimpleLabelSearch(label, val, Sql.Ne),
ge: (label, val) => genericSimpleLabelSearch(label, val, Sql.Gte),
gt: (label, val) => genericSimpleLabelSearch(label, val, Sql.Gt),
le: (label, val) => genericSimpleLabelSearch(label, val, Sql.Lte),
lt: (label, val) => genericSimpleLabelSearch(label, val, Sql.Lt)
}
module.exports.extraLabelsWhere = {
eq: (label, val) => genericExtraLabelSearch(label, val, Sql.Eq),
neq: (label, val) => genericExtraLabelSearch(label, val, Sql.Ne),
ge: (label, val) => genericExtraLabelSearch(label, val, Sql.Gte),
gt: (label, val) => genericExtraLabelSearch(label, val, Sql.Gt),
le: (label, val) => genericExtraLabelSearch(label, val, Sql.Lte),
lt: (label, val) => genericExtraLabelSearch(label, val, Sql.Lt)
}
module.exports.streamWhere = {
eq: (label, val) => genericStreamSearch(label, (_val) => Math.abs(val - _val) < 1e-10),
neq: (label, val) => genericStreamSearch(label, (_val) => Math.abs(val - _val) > 1e-10),
ge: (label, val) => genericStreamSearch(label, (_val) => _val >= val),
gt: (label, val) => genericStreamSearch(label, (_val) => _val > val),
le: (label, val) => genericStreamSearch(label, (_val) => _val <= val),
lt: (label, val) => genericStreamSearch(label, (_val) => _val < val)
}
/**
*
* @param token {Token}
* @param query {Select}
* @returns {Select}
*/
module.exports.eq = (token, query) => {
return genericReq(token, query, 'eq')
}
/**
*
* @param token {Token}
* @param query {Select}
* @returns {Select}
*/
module.exports.neq = (token, query) => {
return genericReq(token, query, 'neq')
}
/**
*
* @param token {Token}
* @param query {Select}
* @returns {Select}
*/
module.exports.gt = (token, query) => {
return genericReq(token, query, 'gt')
}
/**
*
* @param token {Token}
* @param query {Select}
* @returns {Select}
*/
module.exports.ge = (token, query) => {
return genericReq(token, query, 'ge')
}
/**
*
* @param token {Token}
* @param query {Select}
* @returns {Select}
*/
module.exports.lt = (token, query) => {
return genericReq(token, query, 'lt')
}
/**
*
* @param token {Token}
* @param query {Select}
* @returns {Select}
*/
module.exports.le = (token, query) => {
return genericReq(token, query, 'le')
}