diff --git a/packages/server/src/api/controllers/view/utils.js b/packages/server/src/api/controllers/view/utils.js index 59d169ef7f..5bddbf345c 100644 --- a/packages/server/src/api/controllers/view/utils.js +++ b/packages/server/src/api/controllers/view/utils.js @@ -7,6 +7,7 @@ const { } = require("../../../db/utils") const env = require("../../../environment") const { getAppDB } = require("@budibase/backend-core/context") +const viewBuilder = require("./viewBuilder") exports.getView = async viewName => { const db = getAppDB() @@ -114,7 +115,8 @@ exports.deleteView = async viewName => { exports.migrateToInMemoryView = async (db, viewName) => { // delete the view initially const designDoc = await db.get("_design/database") - const view = designDoc.views[viewName] + // run the view back through the view builder to update it + const view = viewBuilder(designDoc.views[viewName].meta) delete designDoc.views[viewName] await db.put(designDoc) await exports.saveView(db, null, viewName, view) @@ -123,7 +125,7 @@ exports.migrateToInMemoryView = async (db, viewName) => { exports.migrateToDesignView = async (db, viewName) => { let view = await db.get(generateMemoryViewID(viewName)) const designDoc = await db.get("_design/database") - designDoc.views[viewName] = view.view + designDoc.views[viewName] = viewBuilder(view.view.meta) await db.put(designDoc) await db.remove(view._id, view._rev) } diff --git a/packages/server/src/api/controllers/view/viewBuilder.js b/packages/server/src/api/controllers/view/viewBuilder.js index 6e2e5c8527..125964a50e 100644 --- a/packages/server/src/api/controllers/view/viewBuilder.js +++ b/packages/server/src/api/controllers/view/viewBuilder.js @@ -10,6 +10,12 @@ const TOKEN_MAP = { OR: "||", } +const CONDITIONS = { + EMPTY: "EMPTY", + NOT_EMPTY: "NOT_EMPTY", + CONTAINS: "CONTAINS", +} + const isEmptyExpression = key => { return `( doc["${key}"] === undefined || @@ -77,13 +83,13 @@ function parseFilterExpression(filters) { expression.push(TOKEN_MAP[filter.conjunction]) } - if (filter.condition === "CONTAINS") { + if (filter.condition === CONDITIONS.CONTAINS) { expression.push( `doc["${filter.key}"].${TOKEN_MAP[filter.condition]}("${filter.value}")` ) - } else if (filter.condition === "EMPTY") { + } else if (filter.condition === CONDITIONS.EMPTY) { expression.push(isEmptyExpression(filter.key)) - } else if (filter.condition === "NOT_EMPTY") { + } else if (filter.condition === CONDITIONS.NOT_EMPTY) { expression.push(`!${isEmptyExpression(filter.key)}`) } else { const value = @@ -125,12 +131,6 @@ function viewTemplate({ field, tableId, groupBy, filters = [], calculation }) { if (filters && filters.length > 0 && filters[0].conjunction) { delete filters[0].conjunction } - const parsedFilters = parseFilterExpression(filters) - const filterExpression = parsedFilters ? `&& (${parsedFilters})` : "" - - const emitExpression = parseEmitExpression(field, groupBy) - - const reduction = field && calculation ? { reduce: `_${calculation}` } : {} let schema = null @@ -139,8 +139,23 @@ function viewTemplate({ field, tableId, groupBy, filters = [], calculation }) { ...(groupBy ? GROUP_PROPERTY : FIELD_PROPERTY), ...SCHEMA_MAP[calculation], } + if ( + !filters.find( + filter => + filter.key === field && filter.condition === CONDITIONS.NOT_EMPTY + ) + ) { + filters.push({ key: field, condition: CONDITIONS.NOT_EMPTY }) + } } + const parsedFilters = parseFilterExpression(filters) + const filterExpression = parsedFilters ? `&& (${parsedFilters})` : "" + + const emitExpression = parseEmitExpression(field, groupBy) + + const reduction = field && calculation ? { reduce: `_${calculation}` } : {} + return { meta: { field,