diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts index 1ea5d068b1..35a88c7577 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/BaseModelSqlv2.ts @@ -1206,14 +1206,34 @@ class BaseModelSqlv2 { private async getSelectQueryBuilderForFormula(column: Column) { const formula = await column.getColOptions(); if (formula.error) throw new Error(`Formula error: ${formula.error}`); - const selectQb = await formulaQueryBuilderv2( + const qb = await formulaQueryBuilderv2( formula.formula, null, this.dbDriver, this.model ); - return selectQb; + try { + // dry run the existing qb.builder to see if it will break the grid view or not + // if so, set formula error and show empty selectQb instead + await this.dbDriver(this.tnPath) + .select(qb.builder) + .as(sanitize(column.title)); + // clean the previous formula error if the formula works this time + if (formula.error) { + await FormulaColumn.update(formula.id, { + error: null, + }); + } + } catch (e) { + console.error(e); + // add formula error to show in UI + await FormulaColumn.update(formula.id, { + error: e.message, + }); + throw new Error(`Formula error: ${e.message}`); + } + return qb; } async getProto() { @@ -1502,7 +1522,6 @@ class BaseModelSqlv2 { const selectQb = await this.getSelectQueryBuilderForFormula( column ); - // todo: verify syntax of as ? / ?? qb.select( this.dbDriver.raw(`?? as ??`, [ selectQb.builder, @@ -1510,7 +1529,10 @@ class BaseModelSqlv2 { ]) ); } catch { - continue; + // return dummy select + qb.select( + this.dbDriver.raw(`'ERR' as ??`, [sanitize(column.title)]) + ); } } break;