From 1eb3bf97adeca63fad2ee4345d2acbcf61069bab Mon Sep 17 00:00:00 2001 From: Pranav C <61551451+pranavxc@users.noreply.github.com> Date: Thu, 5 Aug 2021 20:18:48 +0530 Subject: [PATCH] feat: Add formula functions Added - UPPER, LOWER, LEN, TRIM Signed-off-by: Pranav C <61551451+pranavxc@users.noreply.github.com> --- .../components/editColumn/formulaOptions.vue | 12 ++++- packages/nc-gui/layouts/default.vue | 1 - .../lib/sql/formulaQueryBuilderFromString.ts | 5 ++- .../lib/dataMapper/lib/sql/getFunctionName.ts | 44 +++++++++++++++++++ .../nocodb/src/lib/noco/gql/GqlApiBuilder.ts | 11 ++--- 5 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 packages/nocodb/src/lib/dataMapper/lib/sql/getFunctionName.ts diff --git a/packages/nc-gui/components/project/spreadsheet/components/editColumn/formulaOptions.vue b/packages/nc-gui/components/project/spreadsheet/components/editColumn/formulaOptions.vue index e7887620a7..352542b432 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/editColumn/formulaOptions.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/editColumn/formulaOptions.vue @@ -71,7 +71,12 @@ export default { data: () => ({ formula: {}, // formulas: ['AVERAGE()', 'COUNT()', 'COUNTA()', 'COUNTALL()', 'SUM()', 'MIN()', 'MAX()', 'AND()', 'OR()', 'TRUE()', 'FALSE()', 'NOT()', 'XOR()', 'ISERROR()', 'IF()', 'LEN()', 'MID()', 'LEFT()', 'RIGHT()', 'FIND()', 'CONCATENATE()', 'T()', 'VALUE()', 'ARRAYJOIN()', 'ARRAYUNIQUE()', 'ARRAYCOMPACT()', 'ARRAYFLATTEN()', 'ROUND()', 'ROUNDUP()', 'ROUNDDOWN()', 'INT()', 'EVEN()', 'ODD()', 'MOD()', 'LOG()', 'EXP()', 'POWER()', 'SQRT()', 'CEILING()', 'FLOOR()', 'ABS()', 'RECORD_ID()', 'CREATED_TIME()', 'ERROR()', 'BLANK()', 'YEAR()', 'MONTH()', 'DAY()', 'HOUR()', 'MINUTE()', 'SECOND()', 'TODAY()', 'NOW()', 'WORKDAY()', 'DATETIME_PARSE()', 'DATETIME_FORMAT()', 'SET_LOCALE()', 'SET_TIMEZONE()', 'DATESTR()', 'TIMESTR()', 'TONOW()', 'FROMNOW()', 'DATEADD()', 'WEEKDAY()', 'WEEKNUM()', 'DATETIME_DIFF()', 'WORKDAY_DIFF()', 'IS_BEFORE()', 'IS_SAME()', 'IS_AFTER()', 'REPLACE()', 'REPT()', 'LOWER()', 'UPPER()', 'TRIM()', 'SUBSTITUTE()', 'SEARCH()', 'SWITCH()', 'LAST_MODIFIED_TIME()', 'ENCODE_URL_COMPONENT()', 'REGEX_EXTRACT()', 'REGEX_MATCH()', 'REGEX_REPLACE()'] - availableFunctions: ['AVG', 'ADD', 'CONCAT'], + availableFunctions: [ + 'AVG', 'ADD', 'CONCAT', 'TRIM', + 'UPPER', + 'LOWER', + 'LEN' + ], availableBinOps: ['+', '-', '*', '/'], autocomplete: false, suggestion: null, @@ -246,7 +251,10 @@ export default { this.$nextTick(() => { if (this.$refs.sugOptions[this.selected]) { try { - this.$refs.sugList.$el.scrollTo({ top: this.$refs.sugOptions[this.selected].$el.offsetTop, behavior: 'smooth' }) + this.$refs.sugList.$el.scrollTo({ + top: this.$refs.sugOptions[this.selected].$el.offsetTop, + behavior: 'smooth' + }) } catch (e) { } } diff --git a/packages/nc-gui/layouts/default.vue b/packages/nc-gui/layouts/default.vue index 4e7c10c711..997e63b2ac 100644 --- a/packages/nc-gui/layouts/default.vue +++ b/packages/nc-gui/layouts/default.vue @@ -675,7 +675,6 @@ export default { toggleTreeviewWindow: 'windows/MutToggleTreeviewWindow' }), async loadProjectInfo() { - debugger if (this.$route.params.project_id) { try { const { info } = (await this.$axios.get(`/nc/${this.$route.params.project_id}/projectApiInfo`, { diff --git a/packages/nocodb/src/lib/dataMapper/lib/sql/formulaQueryBuilderFromString.ts b/packages/nocodb/src/lib/dataMapper/lib/sql/formulaQueryBuilderFromString.ts index 7ee15c8a48..3578486542 100644 --- a/packages/nocodb/src/lib/dataMapper/lib/sql/formulaQueryBuilderFromString.ts +++ b/packages/nocodb/src/lib/dataMapper/lib/sql/formulaQueryBuilderFromString.ts @@ -1,4 +1,5 @@ import jsep from 'jsep'; +import getFunctionName from "./getFunctionName"; // todo: switch function based on database @@ -38,7 +39,6 @@ export default function formulaQueryBuilder(tree, alias, knex, aliasToColumn = { return fn(pt.arguments[0], a, prevBinaryOp) } break; - case 'concat': case 'CONCAT': if (knex.clientType() === 'sqlite3') { if (pt.arguments.length > 1) { @@ -53,6 +53,9 @@ export default function formulaQueryBuilder(tree, alias, knex, aliasToColumn = { } } break; + default: + pt.callee.name = getFunctionName(pt.callee.name, knex) + break } return knex.raw(`${pt.callee.name}(${pt.arguments.map(arg => fn(arg).toQuery()).join()})${colAlias}`) diff --git a/packages/nocodb/src/lib/dataMapper/lib/sql/getFunctionName.ts b/packages/nocodb/src/lib/dataMapper/lib/sql/getFunctionName.ts new file mode 100644 index 0000000000..4daa2c4e6a --- /dev/null +++ b/packages/nocodb/src/lib/dataMapper/lib/sql/getFunctionName.ts @@ -0,0 +1,44 @@ +import {XKnex} from "../../index"; + +const pg = { + LEN: 'length' +} + +const mssql = { + LEN: 'LEN' +} + +const mysql2 = { + LEN: 'CHAR_LENGTH' +} + + +const sqlite3 = { + LEN: 'LENGTH' +} + + +const getFunctionName = (name, knex: XKnex) => { + + switch (knex.clientType()) { + + case 'mysql': + case 'mysql2': + return mysql2[name] || name; + break; + case 'pg': + case 'postgre': + return pg[name] || name; + break; + case 'mssql': + return mssql[name] || name; + break; + case 'sqlite': + case 'sqlite3': + return sqlite3[name] || name; + break; + } +} + + +export default getFunctionName; \ No newline at end of file diff --git a/packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts b/packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts index 6bb92f5396..321c8bfc4e 100644 --- a/packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts +++ b/packages/nocodb/src/lib/noco/gql/GqlApiBuilder.ts @@ -1497,7 +1497,7 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { public async onTableUpdate(changeObj: any): Promise { this.log(`onTableUpdate : '%s'`, changeObj.tn); - await super.onTableUpdate(changeObj, async ({ctx, meta}) => { + await super.onTableUpdate(changeObj, async ({ctx}) => { const tn = changeObj.tn; @@ -1515,7 +1515,7 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { const oldSchema = this.schemas[tn]; this.log(`onTableUpdate : Populating new schema for '%s' table`, changeObj.tn); - meta.schema = this.schemas[tn] = GqlXcSchemaFactory.create(this.connectionConfig, this.generateRendererArgs(enabledModelCtx)).getString(); + this.schemas[tn] = GqlXcSchemaFactory.create(this.connectionConfig, this.generateRendererArgs(enabledModelCtx)).getString(); if (oldSchema !== this.schemas[tn]) { this.log(`onTableUpdate : Updating and taking backup of schema - '%s' table`, changeObj.tn); @@ -1530,7 +1530,7 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { } await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', { - schema: meta.schema, + schema: this.schemas[tn], schema_previous: JSON.stringify(previousSchemas) }, { title: tn @@ -2026,10 +2026,11 @@ export class GqlApiBuilder extends BaseApiBuilder implements XcMetaMgr { } await this.xcMeta.metaUpdate(this.projectId, this.dbAlias, 'nc_models', { - schema: meta.schema, + schema: this.schemas[tn], schema_previous: JSON.stringify(previousSchemas) }, { - title: tn + title: tn, + type:'table' }); }