1
0
Fork 0
mirror of synced 2024-10-04 03:54:37 +13:00
budibase/packages/server/src/api/controllers/view/viewBuilder.js
2020-08-24 11:46:28 +01:00

103 lines
1.9 KiB
JavaScript

const TOKEN_MAP = {
EQUALS: "===",
LT: "<",
LTE: "<=",
MT: ">",
MTE: ">=",
CONTAINS: "includes",
AND: "&&",
OR: "||",
}
const SCHEMA_MAP = {
stats: {
group: {
type: "string"
},
sum: {
type: "number"
},
min: {
type: "number"
},
max: {
type: "number"
},
count: {
type: "number"
},
sumsqr: {
type: "number"
},
avg: {
type: "number"
}
}
}
/**
* Iterates through the array of filters to create a JS
* expression that gets used in a CouchDB view.
* @param {Array} filters - an array of filter objects
* @returns {String} JS Expression
*/
function parseFilterExpression(filters) {
const expression = []
for (let filter of filters) {
if (filter.conjunction) expression.push(TOKEN_MAP[filter.conjunction]);
if (filter.condition === "CONTAINS") {
expression.push(
`doc["${filter.key}"].${TOKEN_MAP[filter.condition]}("${
filter.value
}")`)
return
}
expression.push(`doc["${filter.key}"] ${TOKEN_MAP[filter.condition]} "${
filter.value
}"`)
}
return expression.join(" ")
}
function parseEmitExpression(field, groupBy) {
if (field) return `emit(doc["${groupBy || "_id"}"], doc["${field}"]);`
return `emit(doc._id);`
}
function viewTemplate({
field,
modelId,
groupBy,
filters = [],
calculation
}) {
const parsedFilters = parseFilterExpression(filters)
const filterExpression = parsedFilters ? `&& ${parsedFilters}` : ""
const emitExpression = parseEmitExpression(field, groupBy)
const reduction = field ? { reduce: "_stats" } : {}
return {
meta: {
field,
modelId,
groupBy,
filters,
schema: SCHEMA_MAP[calculation],
calculation
},
map: `function (doc) {
if (doc.modelId === "${modelId}" ${filterExpression}) {
${emitExpression}
}
}`,
...reduction
}
}
module.exports = viewTemplate