From d9b972be1b594c4e934aa5f7f53eaf70113d3fa6 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 20:00:08 +0800 Subject: [PATCH 01/20] feat: WEEKDAY validation --- .../components/editColumn/FormulaOptions.vue | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) 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 fbe89f8159..e9cb8f61b0 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/editColumn/FormulaOptions.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/editColumn/FormulaOptions.vue @@ -108,7 +108,6 @@ export default { props: ['nodes', 'column', 'meta', 'isSQLite', 'alias', 'value', 'sqlUi'], 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: formulaList, availableBinOps: ['+', '-', '*', '/', '>', '<', '==', '<=', '>=', '!='], autocomplete: false, @@ -257,7 +256,39 @@ export default { if (parsedTree.callee.type === jsep.IDENTIFIER) { const expectedType = formulas[parsedTree.callee.name].type; if (expectedType === formulaTypes.NUMERIC) { - parsedTree.arguments.map(arg => this.validateAgainstType(arg, expectedType, null, typeErrors)); + if (parsedTree.callee.name === 'WEEKDAY') { + // parsedTree.arguments[0] = date + this.validateAgainstType( + parsedTree.arguments[0], + formulaTypes.DATE, + v => { + if (!(v instanceof Date)) { + typeErrors.add('The first parameter of WEEKDAY() should have date value'); + } + }, + typeErrors + ); + // parsedTree.arguments[1] = startDayOfWeek (optional) + this.validateAgainstType( + parsedTree.arguments[1], + formulaTypes.STRING, + v => { + if ( + typeof v !== 'string' || + !['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday'].includes( + v.toLowerCase() + ) + ) { + typeErrors.add( + 'The second parameter of WEEKDAY() should have the value either "sunday", "monday", "tuesday", "wednesday", "thursday", "friday" or "saturday"' + ); + } + }, + typeErrors + ); + } else { + parsedTree.arguments.map(arg => this.validateAgainstType(arg, expectedType, null, typeErrors)); + } } else if (expectedType === formulaTypes.DATE) { if (parsedTree.callee.name === 'DATEADD') { // parsedTree.arguments[0] = date From d2dd36b5504c63dff2985ffb560cbffe07a95868 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 20:00:17 +0800 Subject: [PATCH 02/20] feat: include WEEKDAY --- packages/nc-gui/helpers/formulaList.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/nc-gui/helpers/formulaList.js b/packages/nc-gui/helpers/formulaList.js index 044764630c..c3ccc0d0b5 100644 --- a/packages/nc-gui/helpers/formulaList.js +++ b/packages/nc-gui/helpers/formulaList.js @@ -471,6 +471,21 @@ const formulas = { 'URL("https://github.com/nocodb/nocodb")', 'URL({column1})' ] + }, + WEEKDAY: { + type: formulaTypes.NUMERIC, + validation: { + args: { + min: 1, + max: 2, + } + }, + description: 'Convert to a hyperlink if it is a valid URL', + syntax: 'WEEKDAY(date, [startDayOfWeek])', + examples: [ + 'WEEKDAY("2021-06-09")', + 'WEEKDAY(CURDATE(), "Monday")' + ] } } From 15a0a73302dd2febde3fec25b425834c456a467b Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 20:00:57 +0800 Subject: [PATCH 03/20] feat: exclude WEEKDAY from column identifier --- packages/nocodb-sdk/src/lib/formulaHelpers.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/nocodb-sdk/src/lib/formulaHelpers.ts b/packages/nocodb-sdk/src/lib/formulaHelpers.ts index 6666c097b8..237e1ac4af 100644 --- a/packages/nocodb-sdk/src/lib/formulaHelpers.ts +++ b/packages/nocodb-sdk/src/lib/formulaHelpers.ts @@ -129,6 +129,7 @@ export function jsepTreeToFormula(node) { 'AVG', 'ADD', 'DATEADD', + 'WEEKDAY', 'AND', 'OR', 'CONCAT', From 8748407bd03f381d903eb269093f968afcc5bb24 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 8 Jul 2022 20:01:10 +0800 Subject: [PATCH 04/20] feat: WEEKDAY logic for mysql --- .../lib/sql/functionMappings/mysql.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts index 9b34375394..784b3046d5 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts @@ -55,6 +55,27 @@ const mysql2 = { END${colAlias}` ); }, + WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { + // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday + const m = { + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6, + }; + const offset = m[pt?.arguments[1]?.value] || 0; + return knex.raw( + `CASE + WHEN WEEKDAY(${fn(pt.arguments[0])}) >= ${offset} THEN + WEEKDAY(${fn(pt.arguments[0])}) - ${offset} + ELSE + 7 - ${offset} + WEEKDAY(${fn(pt.arguments[0])}) + END${colAlias}` + ); + }, }; export default mysql2; From 3c7d3028e934ed554d4993071766898b535592e6 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 11:56:52 +0800 Subject: [PATCH 05/20] feat: WEEKDAY logic for sqlite --- .../lib/sql/functionMappings/sqlite.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts index e5ba36ed32..343bbe2856 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts @@ -75,6 +75,25 @@ const sqlite3 = { END${colAlias}` ); }, + + WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { + // strftime('%w', date) - day of week 0 - 6 with Sunday == 0 + // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday + const m = { + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6, + }; + return knex.raw( + `strftime('%w', ${fn(pt.arguments[0])}, 'weekday ${ + m[pt?.arguments[1]?.value.toLowerCase()] || 0 + }')${colAlias}` + ); + }, }; export default sqlite3; From 9a17417127718fcc695529a5bf666815d57bd10a Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 12:30:53 +0800 Subject: [PATCH 06/20] fix: add toLowerCase() to pt?.arguments[1]?.value --- .../lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts index 784b3046d5..9c35ee09ad 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts @@ -66,7 +66,7 @@ const mysql2 = { saturday: 5, sunday: 6, }; - const offset = m[pt?.arguments[1]?.value] || 0; + const offset = m[pt?.arguments[1]?.value.toLowerCase()] || 0; return knex.raw( `CASE WHEN WEEKDAY(${fn(pt.arguments[0])}) >= ${offset} THEN From 82d47b4d93eabfe402a1bbe22987611b9c8da604 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 12:33:32 +0800 Subject: [PATCH 07/20] chore: revise weekday logic using mod --- .../db/sql-data-mapper/lib/sql/functionMappings/mysql.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts index 9c35ee09ad..9d8df34256 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts @@ -68,12 +68,7 @@ const mysql2 = { }; const offset = m[pt?.arguments[1]?.value.toLowerCase()] || 0; return knex.raw( - `CASE - WHEN WEEKDAY(${fn(pt.arguments[0])}) >= ${offset} THEN - WEEKDAY(${fn(pt.arguments[0])}) - ${offset} - ELSE - 7 - ${offset} + WEEKDAY(${fn(pt.arguments[0])}) - END${colAlias}` + `(WEEKDAY(${fn(pt.arguments[0])}) - ${offset} % 7 + 7) % 7 ${colAlias}` ); }, }; From fdb6b0c6d25ed1995633390e9111790582143650 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 12:33:45 +0800 Subject: [PATCH 08/20] feat: WEEKDAY logic for pg --- .../lib/sql/functionMappings/pg.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts index 21d8ff53ea..2fdef7fa39 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts @@ -42,6 +42,25 @@ const pg = { )}')::interval${colAlias}` ); }, + WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { + // isodow: the day of the week as Monday (1) to Sunday (7) + // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday + const m = { + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6, + }; + const offset = m[pt?.arguments[1]?.value.toLowerCase()] || 0; + return knex.raw( + `(EXTRACT(ISODOW FROM ${fn( + pt.arguments[0] + )}) - 1 - ${offset} % 7 + 7) % 7 ${colAlias}` + ); + }, }; export default pg; From 6064f9f20190a5ce027495f42e90752cddad7aa3 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 13:42:07 +0800 Subject: [PATCH 09/20] feat: WEEKDAY logic for mssql --- .../lib/sql/functionMappings/mssql.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts index a95f69e6c4..78c4f5c142 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts @@ -108,6 +108,24 @@ const mssql = { END${colAlias}` ); }, + WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { + // DATEPART(WEEKDAY, DATE): sunday = 1, monday = 2, ..., saturday = 7 + // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday + const m = { + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6, + }; + return knex.raw( + `(DATEPART(WEEKDAY, ${fn(pt.arguments[0])}) - 2 - ${ + m[pt?.arguments[1]?.value.toLowerCase()] || 0 + } % 7 + 7) % 7 ${colAlias}` + ); + }, }; export default mssql; From 47586fc3568306fea59ba2591e48e9822de1414b Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 13:50:55 +0800 Subject: [PATCH 10/20] feat: add weekday fn to helpers --- .../lib/sql/helpers/formulaFnHelper.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts new file mode 100644 index 0000000000..8a55ba3145 --- /dev/null +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts @@ -0,0 +1,25 @@ +export function getWeekdayByText(v: string) { + const m = { + monday: 0, + tuesday: 1, + wednesday: 2, + thursday: 3, + friday: 4, + saturday: 5, + sunday: 6, + }; + return m[v?.toLowerCase() || 'monday']; +} + +export function getWeekdayByIndex(idx: number): string { + const m = { + 0: 'monday', + 1: 'tuesday', + 2: 'wednesday', + 3: 'thursday', + 4: 'friday', + 5: 'saturday', + 6: 'sunday', + }; + return m[idx || 0]; +} From 3893b9d3f66bfcdc7817b909f11a6ff014785046 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 13:51:22 +0800 Subject: [PATCH 11/20] refactor: use getWeekdayByText instead --- .../lib/sql/functionMappings/mssql.ts | 16 ++++------------ .../lib/sql/functionMappings/mysql.ts | 15 ++++----------- .../lib/sql/functionMappings/pg.ts | 17 ++++------------- .../lib/sql/functionMappings/sqlite.ts | 16 ++++------------ 4 files changed, 16 insertions(+), 48 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts index 78c4f5c142..48d0fe0472 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts @@ -1,5 +1,6 @@ import { MapFnArgs } from '../mapFunctionName'; import commonFns from './commonFns'; +import { getWeekdayByText } from '../helpers/formulaFnHelper'; const mssql = { ...commonFns, @@ -111,19 +112,10 @@ const mssql = { WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { // DATEPART(WEEKDAY, DATE): sunday = 1, monday = 2, ..., saturday = 7 // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday - const m = { - monday: 0, - tuesday: 1, - wednesday: 2, - thursday: 3, - friday: 4, - saturday: 5, - sunday: 6, - }; return knex.raw( - `(DATEPART(WEEKDAY, ${fn(pt.arguments[0])}) - 2 - ${ - m[pt?.arguments[1]?.value.toLowerCase()] || 0 - } % 7 + 7) % 7 ${colAlias}` + `(DATEPART(WEEKDAY, ${fn(pt.arguments[0])}) - 2 - ${getWeekdayByText( + pt?.arguments[1]?.value + )} % 7 + 7) % 7 ${colAlias}` ); }, }; diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts index 9d8df34256..089485cf0e 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts @@ -1,5 +1,6 @@ import { MapFnArgs } from '../mapFunctionName'; import commonFns from './commonFns'; +import { getWeekdayByText } from '../helpers/formulaFnHelper'; const mysql2 = { ...commonFns, @@ -57,18 +58,10 @@ const mysql2 = { }, WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday - const m = { - monday: 0, - tuesday: 1, - wednesday: 2, - thursday: 3, - friday: 4, - saturday: 5, - sunday: 6, - }; - const offset = m[pt?.arguments[1]?.value.toLowerCase()] || 0; return knex.raw( - `(WEEKDAY(${fn(pt.arguments[0])}) - ${offset} % 7 + 7) % 7 ${colAlias}` + `(WEEKDAY(${fn(pt.arguments[0])}) - ${getWeekdayByText( + pt?.arguments[1]?.value + )} % 7 + 7) % 7 ${colAlias}` ); }, }; diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts index 2fdef7fa39..0e4176ce27 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts @@ -1,5 +1,6 @@ import { MapFnArgs } from '../mapFunctionName'; import commonFns from './commonFns'; +import { getWeekdayByText } from '../helpers/formulaFnHelper'; const pg = { ...commonFns, @@ -45,20 +46,10 @@ const pg = { WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { // isodow: the day of the week as Monday (1) to Sunday (7) // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday - const m = { - monday: 0, - tuesday: 1, - wednesday: 2, - thursday: 3, - friday: 4, - saturday: 5, - sunday: 6, - }; - const offset = m[pt?.arguments[1]?.value.toLowerCase()] || 0; return knex.raw( - `(EXTRACT(ISODOW FROM ${fn( - pt.arguments[0] - )}) - 1 - ${offset} % 7 + 7) % 7 ${colAlias}` + `(EXTRACT(ISODOW FROM ${fn(pt.arguments[0])}) - 1 - ${getWeekdayByText( + pt?.arguments[1]?.value + )} % 7 + 7) % 7 ${colAlias}` ); }, }; diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts index 343bbe2856..69d7ec1f8e 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts @@ -1,5 +1,6 @@ import { MapFnArgs } from '../mapFunctionName'; import commonFns from './commonFns'; +import { getWeekdayByText } from '../helpers/formulaFnHelper'; const sqlite3 = { ...commonFns, @@ -79,19 +80,10 @@ const sqlite3 = { WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { // strftime('%w', date) - day of week 0 - 6 with Sunday == 0 // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday - const m = { - monday: 0, - tuesday: 1, - wednesday: 2, - thursday: 3, - friday: 4, - saturday: 5, - sunday: 6, - }; return knex.raw( - `strftime('%w', ${fn(pt.arguments[0])}, 'weekday ${ - m[pt?.arguments[1]?.value.toLowerCase()] || 0 - }')${colAlias}` + `strftime('%w', ${fn(pt.arguments[0])}, 'weekday ${getWeekdayByText( + pt?.arguments[1]?.value + )}')${colAlias}` ); }, }; From 6a31fb5a036c604e1d1daf4a4c811677a6024221 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 14:02:34 +0800 Subject: [PATCH 12/20] fix: update description & examples of WEEKDAY --- packages/nc-gui/helpers/formulaList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nc-gui/helpers/formulaList.js b/packages/nc-gui/helpers/formulaList.js index c3ccc0d0b5..4364a475fe 100644 --- a/packages/nc-gui/helpers/formulaList.js +++ b/packages/nc-gui/helpers/formulaList.js @@ -480,11 +480,11 @@ const formulas = { max: 2, } }, - description: 'Convert to a hyperlink if it is a valid URL', + description: 'Returns the day of the week as an integer between 0 and 6 inclusive starting from Monday by default', syntax: 'WEEKDAY(date, [startDayOfWeek])', examples: [ 'WEEKDAY("2021-06-09")', - 'WEEKDAY(CURDATE(), "Monday")' + 'WEEKDAY(NOW(), "sunday")' ] } } From bc5647eaaf754b85bf73d109e371fb0560a0fdfa Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 14:15:47 +0800 Subject: [PATCH 13/20] fix: WEEKDAY logic for sqlite --- .../lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts index 69d7ec1f8e..e6f9f99a7e 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts @@ -81,9 +81,9 @@ const sqlite3 = { // strftime('%w', date) - day of week 0 - 6 with Sunday == 0 // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday return knex.raw( - `strftime('%w', ${fn(pt.arguments[0])}, 'weekday ${getWeekdayByText( + `(strftime('%w', ${fn(pt.arguments[0])}) - 1 - ${getWeekdayByText( pt?.arguments[1]?.value - )}')${colAlias}` + )} % 7 + 7) % 7 ${colAlias}` ); }, }; From 286981348405d95abe079d1128c11ec267a08c99 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 14:16:22 +0800 Subject: [PATCH 14/20] docs: include WEEKDAY in formula --- packages/noco-docs/content/en/setup-and-usages/formulas.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/noco-docs/content/en/setup-and-usages/formulas.md b/packages/noco-docs/content/en/setup-and-usages/formulas.md index 53044134a6..be5dbaa939 100644 --- a/packages/noco-docs/content/en/setup-and-usages/formulas.md +++ b/packages/noco-docs/content/en/setup-and-usages/formulas.md @@ -90,6 +90,10 @@ Example: ({Column1} + ({Column2} * {Column3}) / (3 - $Column4$ )) | | | `DATEADD(date, 1, 'month')` | Supposing {DATE_COL} is 2022-03-14 03:14. The result is 2022-04-14 03:14. | DateTime columns and negative values are supported. Example: `DATEADD(DATE_TIME_COL, -1, 'month')` | | | | `DATEADD(date, 1, 'year')` | Supposing {DATE_COL} is 2022-03-14 03:14. The result is 2023-03-14 03:14. | DateTime columns and negative values are supported. Example: `DATEADD(DATE_TIME_COL, -1, 'year')` | | | | `IF(NOW() < DATEADD(date,10,'day'), "true", "false")` | If the current date is less than {DATE_COL} plus 10 days, it returns true. Otherwise, it returns false. | DateTime columns and negative values are supported. | +| | | `IF(NOW() < DATEADD(date,10,'day'), "true", "false")` | If the current date is less than {DATE_COL} plus 10 days, it returns true. Otherwise, it returns false. | DateTime columns and negative values are supported. | +| **WEEKDAY** | `WEEKDAY(date, [startDayOfWeek])` | `WEEKDAY(NOW())` | If today is Monday, it returns 0 | Returns the day of the week as an integer between 0 and 6 inclusive starting from Monday by default. You can optionally change the start day of the week by specifying in the second argument | +| | | `WEEKDAY(NOW(), "sunday")` | If today is Monday, it returns 1 | Get the week day of NOW() with the first day set as sunday | + ### Logical Operators | Operator | Sample | Description | From 464c70c47fa779e9e195ab9ff3aa18f6061af8ab Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 14:22:02 +0800 Subject: [PATCH 15/20] refactor: formulaFnHelper --- .../sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts index 8a55ba3145..f8057a2473 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/formulaFnHelper.ts @@ -1,5 +1,5 @@ export function getWeekdayByText(v: string) { - const m = { + return { monday: 0, tuesday: 1, wednesday: 2, @@ -7,12 +7,11 @@ export function getWeekdayByText(v: string) { friday: 4, saturday: 5, sunday: 6, - }; - return m[v?.toLowerCase() || 'monday']; + }[v?.toLowerCase() || 'monday']; } export function getWeekdayByIndex(idx: number): string { - const m = { + return { 0: 'monday', 1: 'tuesday', 2: 'wednesday', @@ -20,6 +19,5 @@ export function getWeekdayByIndex(idx: number): string { 4: 'friday', 5: 'saturday', 6: 'sunday', - }; - return m[idx || 0]; + }[idx || 0]; } From 4b45bd1ff065612082cdcfc599c0527e33e8628c Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 17:51:59 +0800 Subject: [PATCH 16/20] feat: add validateDateWithUnknownFormat --- packages/nc-gui/helpers/dateFormatHelper.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/nc-gui/helpers/dateFormatHelper.js b/packages/nc-gui/helpers/dateFormatHelper.js index 032e44f829..4142dc3ea6 100644 --- a/packages/nc-gui/helpers/dateFormatHelper.js +++ b/packages/nc-gui/helpers/dateFormatHelper.js @@ -1,3 +1,7 @@ +import dayjs from 'dayjs'; +const customParseFormat = require('dayjs/plugin/customParseFormat'); +dayjs.extend(customParseFormat); + export const dateFormat = [ 'DD-MM-YYYY', 'MM-DD-YYYY', 'YYYY-MM-DD', 'DD/MM/YYYY', 'MM/DD/YYYY', 'YYYY/MM/DD', @@ -6,4 +10,12 @@ export const dateFormat = [ export function validateDateFormat(v) { return dateFormat.includes(v) +} + +export function validateDateWithUnknownFormat(v) { + let res = 0; + for (const format of dateFormat) { + res |= dayjs(v.toString(), format, true).isValid(); + } + return res; } \ No newline at end of file From 01dad4e2ffe4182cb97a94a5f7c6588749ac602e Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 17:52:58 +0800 Subject: [PATCH 17/20] fix: validate date using dayjs --- .../spreadsheet/components/editColumn/FormulaOptions.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 718e02b384..19cd252e8e 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/editColumn/FormulaOptions.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/editColumn/FormulaOptions.vue @@ -100,6 +100,7 @@ import jsep from 'jsep'; import { UITypes, jsepCurlyHook } from 'nocodb-sdk'; import { getUIDTIcon } from '~/components/project/spreadsheet/helpers/uiTypes'; import formulaList, { formulas, formulaTypes } from '@/helpers/formulaList'; +import { validateDateWithUnknownFormat } from '@/helpers/dateFormatHelper'; import { getWordUntilCaret, insertAtCursor } from '@/helpers'; import NcAutocompleteTree from '@/helpers/NcAutocompleteTree'; @@ -265,7 +266,7 @@ export default { parsedTree.arguments[0], formulaTypes.DATE, v => { - if (!(v instanceof Date)) { + if (!validateDateWithUnknownFormat(v)) { typeErrors.add('The first parameter of WEEKDAY() should have date value'); } }, @@ -299,7 +300,7 @@ export default { parsedTree.arguments[0], formulaTypes.DATE, v => { - if (!(v instanceof Date)) { + if (!validateDateWithUnknownFormat(v)) { typeErrors.add('The first parameter of DATEADD() should have date value'); } }, From 0d026a59710338d3e4dfbe41217c36ff108a02d5 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 18:02:46 +0800 Subject: [PATCH 18/20] feat: handle string date --- .../db/sql-data-mapper/lib/sql/functionMappings/mssql.ts | 7 ++++++- .../db/sql-data-mapper/lib/sql/functionMappings/mysql.ts | 7 ++++++- .../lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts | 7 ++++++- .../db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts | 7 ++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts index 48d0fe0472..1358a87411 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mssql.ts @@ -1,3 +1,4 @@ +import dayjs from 'dayjs'; import { MapFnArgs } from '../mapFunctionName'; import commonFns from './commonFns'; import { getWeekdayByText } from '../helpers/formulaFnHelper'; @@ -113,7 +114,11 @@ const mssql = { // DATEPART(WEEKDAY, DATE): sunday = 1, monday = 2, ..., saturday = 7 // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday return knex.raw( - `(DATEPART(WEEKDAY, ${fn(pt.arguments[0])}) - 2 - ${getWeekdayByText( + `(DATEPART(WEEKDAY, ${ + pt.arguments[0].type === 'Literal' + ? `'${dayjs(fn(pt.arguments[0])).format('YYYY-MM-DD')}'` + : fn(pt.arguments[0]) + }) - 2 - ${getWeekdayByText( pt?.arguments[1]?.value )} % 7 + 7) % 7 ${colAlias}` ); diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts index 089485cf0e..babad78588 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/mysql.ts @@ -1,3 +1,4 @@ +import dayjs from 'dayjs'; import { MapFnArgs } from '../mapFunctionName'; import commonFns from './commonFns'; import { getWeekdayByText } from '../helpers/formulaFnHelper'; @@ -59,7 +60,11 @@ const mysql2 = { WEEKDAY: ({ fn, knex, pt, colAlias }: MapFnArgs) => { // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday return knex.raw( - `(WEEKDAY(${fn(pt.arguments[0])}) - ${getWeekdayByText( + `(WEEKDAY(${ + pt.arguments[0].type === 'Literal' + ? `'${dayjs(fn(pt.arguments[0])).format('YYYY-MM-DD')}'` + : fn(pt.arguments[0]) + }) - ${getWeekdayByText( pt?.arguments[1]?.value )} % 7 + 7) % 7 ${colAlias}` ); diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts index 0e4176ce27..4e34629bca 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/pg.ts @@ -1,3 +1,4 @@ +import dayjs from 'dayjs'; import { MapFnArgs } from '../mapFunctionName'; import commonFns from './commonFns'; import { getWeekdayByText } from '../helpers/formulaFnHelper'; @@ -47,7 +48,11 @@ const pg = { // isodow: the day of the week as Monday (1) to Sunday (7) // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday return knex.raw( - `(EXTRACT(ISODOW FROM ${fn(pt.arguments[0])}) - 1 - ${getWeekdayByText( + `(EXTRACT(ISODOW FROM ${ + pt.arguments[0].type === 'Literal' + ? `date '${dayjs(fn(pt.arguments[0])).format('YYYY-MM-DD')}'` + : fn(pt.arguments[0]) + }) - 1 - ${getWeekdayByText( pt?.arguments[1]?.value )} % 7 + 7) % 7 ${colAlias}` ); diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts index e6f9f99a7e..4a12f5ee4b 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/functionMappings/sqlite.ts @@ -1,3 +1,4 @@ +import dayjs from 'dayjs'; import { MapFnArgs } from '../mapFunctionName'; import commonFns from './commonFns'; import { getWeekdayByText } from '../helpers/formulaFnHelper'; @@ -81,7 +82,11 @@ const sqlite3 = { // strftime('%w', date) - day of week 0 - 6 with Sunday == 0 // WEEKDAY() returns an index from 0 to 6 for Monday to Sunday return knex.raw( - `(strftime('%w', ${fn(pt.arguments[0])}) - 1 - ${getWeekdayByText( + `(strftime('%w', ${ + pt.arguments[0].type === 'Literal' + ? `'${dayjs(fn(pt.arguments[0])).format('YYYY-MM-DD')}'` + : fn(pt.arguments[0]) + }) - 1 - ${getWeekdayByText( pt?.arguments[1]?.value )} % 7 + 7) % 7 ${colAlias}` ); From b2149708c5df73c6dbdff7158748c41fd7e94e43 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 18:15:54 +0800 Subject: [PATCH 19/20] cypress: add WEEKDAY cases --- .../integration/common/3b_formula_column.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/scripts/cypress/integration/common/3b_formula_column.js b/scripts/cypress/integration/common/3b_formula_column.js index 9fba2ab366..c7bab052c4 100644 --- a/scripts/cypress/integration/common/3b_formula_column.js +++ b/scripts/cypress/integration/common/3b_formula_column.js @@ -194,9 +194,25 @@ export const genTest = (apiType, dbType) => { rowValidation("NC_MATH_0", RESULT_MATH_0); }); - it("Formula: CONCAT, LOWER, UPPER, TRIM", () => { + it("Formula: WEEKDAY", () => { editColumnByName( "NC_MATH_0", + "NC_WEEKDAY_0", + `WEEKDAY("2022-07-19")` + ); + rowValidation("NC_WEEKDAY_0", 1); + + editColumnByName( + "NC_WEEKDAY_0", + "NC_WEEKDAY_1", + `WEEKDAY("2022-07-19", "sunday")` + ); + rowValidation("NC_WEEKDAY_1", 2); + }); + + it("Formula: CONCAT, LOWER, UPPER, TRIM", () => { + editColumnByName( + "NC_WEEKDAY_1", "NC_STR_1", `CONCAT(UPPER({City}), LOWER({City}), TRIM(' trimmed '))` ); From e0699acc4e2954fcf5367a05320f2bea1ffc4087 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Mon, 18 Jul 2022 18:41:43 +0800 Subject: [PATCH 20/20] cypress: fix weekday test --- .../cypress/integration/common/3b_formula_column.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/cypress/integration/common/3b_formula_column.js b/scripts/cypress/integration/common/3b_formula_column.js index c7bab052c4..d8251535a7 100644 --- a/scripts/cypress/integration/common/3b_formula_column.js +++ b/scripts/cypress/integration/common/3b_formula_column.js @@ -153,6 +153,8 @@ export const genTest = (apiType, dbType) => { let RESULT_MATH_0 = []; let RESULT_MATH_1 = []; let RESULT_MATH_2 = []; + let RESULT_WEEKDAY_0 = []; + let RESULT_WEEKDAY_1 = []; for (let i = 0; i < 10; i++) { // CONCAT, LOWER, UPPER, TRIM @@ -184,6 +186,11 @@ export const genTest = (apiType, dbType) => { Math.pow(cityId[i], 3) + Math.sqrt(countryId[i]) ); + + // WEEKDAY: starts from Monday + RESULT_WEEKDAY_0[i] = 1; + // WEEKDAY: starts from Sunday + RESULT_WEEKDAY_1[i] = 2; } it("Formula: ADD, AVG, LEN", () => { @@ -200,14 +207,14 @@ export const genTest = (apiType, dbType) => { "NC_WEEKDAY_0", `WEEKDAY("2022-07-19")` ); - rowValidation("NC_WEEKDAY_0", 1); + rowValidation("NC_WEEKDAY_0", RESULT_WEEKDAY_0); editColumnByName( "NC_WEEKDAY_0", "NC_WEEKDAY_1", `WEEKDAY("2022-07-19", "sunday")` ); - rowValidation("NC_WEEKDAY_1", 2); + rowValidation("NC_WEEKDAY_1", RESULT_WEEKDAY_1); }); it("Formula: CONCAT, LOWER, UPPER, TRIM", () => {