diff --git a/packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts b/packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts index f1ac991183..3a6dcb8775 100644 --- a/packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts +++ b/packages/nocodb/src/db/formulav2/formulaQueryBuilderv2.ts @@ -419,7 +419,7 @@ async function _formulaQueryBuilder( '', lookupModel, aliasToColumn, - formulaOption.getParsedTree() + formulaOption.getParsedTree(), ); if (isMany) { const qb = selectQb; @@ -963,6 +963,7 @@ export default async function formulaQueryBuilderv2( aliasToColumn = {}, tableAlias?: string, validateFormula = false, + parsedTree?: any, ) { const knex = baseModelSqlv2.dbDriver; // register jsep curly hook once only @@ -975,9 +976,10 @@ export default async function formulaQueryBuilderv2( model, aliasToColumn, tableAlias, - await column - ?.getColOptions() - .then((formula) => formula?.getParsedTree()), + parsedTree ?? + (await column + ?.getColOptions() + .then((formula) => formula?.getParsedTree())), ); if (!validateFormula) return qb; diff --git a/packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts b/packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts index 6dedcf2843..2df5d90b5a 100644 --- a/packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts +++ b/packages/nocodb/src/meta/migrations/XcMigrationSourcev2.ts @@ -24,6 +24,7 @@ import * as nc_034_erd_filter_and_notification from '~/meta/migrations/v2/nc_034 import * as nc_035_add_username_to_users from '~/meta/migrations/v2/nc_035_add_username_to_users'; import * as nc_036_base_deleted from '~/meta/migrations/v2/nc_036_base_deleted'; import * as nc_037_rename_project_and_base from '~/meta/migrations/v2/nc_037_rename_project_and_base'; +import * as nc_038_formula_parsed_tree_column from '~/meta/migrations/v2/nc_038_formula_parsed_tree_column'; // Create a custom migration source class export default class XcMigrationSourcev2 { @@ -59,6 +60,7 @@ export default class XcMigrationSourcev2 { 'nc_035_add_username_to_users', 'nc_036_base_deleted', 'nc_037_rename_project_and_base', + 'nc_038_formula_parsed_tree_column' ]); } @@ -120,6 +122,8 @@ export default class XcMigrationSourcev2 { return nc_036_base_deleted; case 'nc_037_rename_project_and_base': return nc_037_rename_project_and_base; + case 'nc_038_formula_parsed_tree_column': + return nc_038_formula_parsed_tree_column; } } } diff --git a/packages/nocodb/src/models/Column.ts b/packages/nocodb/src/models/Column.ts index f9996aea0a..2d76ed8860 100644 --- a/packages/nocodb/src/models/Column.ts +++ b/packages/nocodb/src/models/Column.ts @@ -308,6 +308,7 @@ export default class Column implements ColumnType { fk_column_id: colId, formula: column.formula, formula_raw: column.formula_raw, + parsed_tree: column.parsed_tree, }, ncMeta, ); diff --git a/packages/nocodb/src/models/FormulaColumn.ts b/packages/nocodb/src/models/FormulaColumn.ts index 4c786125e9..f807737286 100644 --- a/packages/nocodb/src/models/FormulaColumn.ts +++ b/packages/nocodb/src/models/FormulaColumn.ts @@ -11,8 +11,10 @@ export default class FormulaColumn { error: string; private parsed_tree?: any; - constructor(data: Partial) { - Object.assign(this, data); + constructor(data: Partial & { parsed_tree?: any }) { + const { parsed_tree, ...rest } = data; + this.parsed_tree = parsed_tree; + Object.assign(this, rest); } public static async insert( diff --git a/packages/nocodb/src/services/columns.service.ts b/packages/nocodb/src/services/columns.service.ts index 48c2f30464..edace7a76d 100644 --- a/packages/nocodb/src/services/columns.service.ts +++ b/packages/nocodb/src/services/columns.service.ts @@ -5,7 +5,8 @@ import { isVirtualCol, substituteColumnAliasWithIdInFormula, substituteColumnIdWithAliasInFormula, - UITypes, validateFormulaAndExtractTreeWithType, + UITypes, + validateFormulaAndExtractTreeWithType, } from 'nocodb-sdk'; import { pluralize, singularize } from 'inflection'; import hash from 'object-hash'; @@ -184,6 +185,7 @@ export class ColumnsService { let colBody = { ...param.column } as Column & { formula?: string; formula_raw?: string; + parsed_tree?: any; }; if ( [ @@ -208,6 +210,10 @@ export class ColumnsService { colBody.formula_raw || colBody.formula, table.columns, ); + colBody.parsed_tree = validateFormulaAndExtractTreeWithType( + colBody.formula_raw || colBody.formula, + table.columns, + ); try { const baseModel = await reuseOrSave('baseModel', reuse, async () => @@ -227,6 +233,7 @@ export class ColumnsService { {}, null, true, + colBody.parsed_tree ); } catch (e) { console.error(e); @@ -931,6 +938,7 @@ export class ColumnsService { ]); await FormulaColumn.update(c.id, { formula_raw: new_formula_raw, + parsed_tree: validateFormulaAndExtractTreeWithType(new_formula_raw, table.columns) }); } } @@ -992,6 +1000,10 @@ export class ColumnsService { ]); await FormulaColumn.update(c.id, { formula_raw: new_formula_raw, + parsed_tree: validateFormulaAndExtractTreeWithType( + new_formula_raw, + table.columns, + ), }); } }