Browse Source

Merge pull request #1816 from mertmit/fix-dateadd-issue

fix: DATEADD negative intervals
pull/1845/head
աɨռɢӄաօռɢ 3 years ago committed by GitHub
parent
commit
972b5f86f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      packages/nc-gui/components/project/spreadsheet/components/virtualCell.vue
  2. 23
      packages/nc-gui/components/project/spreadsheet/components/virtualCell/formulaCell.vue
  3. 12
      packages/noco-docs/content/en/setup-and-usages/formulas.md
  4. 17
      packages/nocodb/src/lib/dataMapper/lib/sql/formulav2/formulaQueryBuilderv2.ts
  5. 23
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/mssql.ts
  6. 16
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/mysql.ts
  7. 29
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/pg.ts
  8. 25
      packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/sqlite.ts

1
packages/nc-gui/components/project/spreadsheet/components/virtualCell.vue

@ -85,6 +85,7 @@
v-else-if="formula"
:row="row"
:column="column"
:client="nodes.dbConnection.client"
/>
<rollup-cell
v-else-if="rollup"

23
packages/nc-gui/components/project/spreadsheet/components/virtualCell/formulaCell.vue

@ -11,19 +11,27 @@
</v-tooltip>
<div v-else-if="urls" v-html="urls" />
<div v-else>
{{ row[column.title] }}
{{ result }}
</div>
</template>
<script>
import dayjs from 'dayjs'
export default {
name: 'FormulaCell',
props: { column: Object, row: Object },
props: { column: Object, row: Object, client: String },
computed: {
result() {
if (this.client === 'pg') {
return this.handleTZ(this.row[this.column.title])
}
return this.row[this.column.title]
},
urls() {
if (!this.row[this.column.title]) { return }
const rawText = this.row[this.column.title].toString()
const rawText = this.result.toString()
let found = false
const out = rawText.replace(/URI::\((.*?)\)/g, (_, url) => {
found = true
@ -36,6 +44,15 @@ export default {
return found && out
}
},
methods: {
// handle date returned from PostgreSQL
handleTZ(val) {
if (!val) { return }
return val.replace(/((?:-?(?:[1-9][0-9]*)?[0-9]{4})-(?:1[0-2]|0[1-9])-(?:3[01]|0[1-9]|[12][0-9])T(?:2[0-3]|[01][0-9]):(?:[0-5][0-9]):(?:[0-5][0-9])(?:\.[0-9]+)?(?:Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9]))/g, (i, v) => {
return dayjs(v).format('YYYY-MM-DD HH:mm')
})
}
}
}
</script>

12
packages/noco-docs/content/en/setup-and-usages/formulas.md

@ -81,12 +81,12 @@ Example: (column1 + (column2 * column3) / (3 - column4 ))
### Date Functions
| Name | Syntax | Sample | Output |
|-------------|-----------------------------------------------------------|-------------------------------------------------------|-------------------------------------------------------------------------------------------------------|
| **DATEADD** | `DATEADD(DATE_COL, 1, 'day')` | `DATEADD(date, 1, 'day')` | Supposing the DATE_COL is 2022-03-14. The result is 2022-03-15. |
| | `DATEADD(DATE_TIME_COL, 2, 'month')` | `DATEADD(datetime, 2, 'month')` | Supposing the DATE_COL is 2022-03-14 03:14. The result is 2022-05-14 03:14. |
| | `IF(NOW() < DATE_COL, "true", "false")` | `IF(NOW() < date, "true", "false")` | If current date is less than DATE_COL, it returns true. Otherwise, it returns false. |
| | `IF(NOW() < DATEADD(DATE_COL,10,'day'), "true", "false")` | `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. |
| Name | Syntax | Sample | Output | Remark |
|---|---|---|---|---|
| **DATEADD** | `DATEADD(DATE_COL, 1, 'day')` | `DATEADD(date, 1, 'day')` | Supposing the DATE_COL is 2022-03-14. The result is 2022-03-15. | DateTime columns and negative values are supported. Example: `DATEADD(DATE_TIME_COL, -1, 'day')` |
| | `DATEADD(DATE_COL, 2, 'month')` | `DATEADD(date, 2, 'month')` | Supposing the DATE_COL is 2022-03-14 03:14. The result is 2022-05-14 03:14. | DateTime columns and negative values are supported. Example: `DATEADD(DATE_TIME_COL, -2, 'month')` |
| | `IF(NOW() < DATE_COL, "true", "false")` | `IF(NOW() < date, "true", "false")` | If current date is less than DATE_COL, it returns true. Otherwise, it returns false. | DateTime columns and negative values are supported. |
| | `IF(NOW() < DATEADD(DATE_COL,10,'day'), "true", "false")` | `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. |
### Logical Operators

17
packages/nocodb/src/lib/dataMapper/lib/sql/formulav2/formulaQueryBuilderv2.ts

@ -564,15 +564,6 @@ export default async function formulaQueryBuilderv2(
}
}
break;
case 'DATEADD':
if (pt.arguments[1].value) {
pt.callee.name = 'DATE_ADD';
return fn(pt, alias, prevBinaryOp);
} else if (pt.arguments[1].operator == '-') {
pt.callee.name = 'DATE_SUB';
return fn(pt, alias, prevBinaryOp);
}
break;
case 'URL':
return fn(
{
@ -654,6 +645,14 @@ export default async function formulaQueryBuilderv2(
query.wrap('(', ')');
}
return query;
} else if (pt.type === 'UnaryExpression') {
const query = knex.raw(
`${pt.operator}${fn(pt.argument, null, pt.operator).toQuery()}${colAlias}`
);
if (prevBinaryOp && pt.operator !== prevBinaryOp) {
query.wrap('(', ')');
}
return query;
}
};
return { builder: fn(tree, alias) };

23
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/mssql.ts

@ -89,31 +89,16 @@ const mssql = {
.raw(`CAST(${args.fn(args.pt.arguments[0])} as FLOAT)${args.colAlias}`)
.wrap('(', ')');
},
DATE_ADD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
DATEADD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
const dateIN = fn(pt.arguments[1]);
return knex.raw(
`CASE
WHEN ${fn(pt.arguments[0])} LIKE '%:%' THEN
FORMAT(DATEADD(${String(fn(pt.arguments[2])).replace(/["']/g, '')},
+${fn(pt.arguments[1])}, ${fn(pt.arguments[0])}), 'yyyy-MM-dd HH:mm')
${dateIN > 0 ? '+' : ''}${fn(pt.arguments[1])}, ${fn(pt.arguments[0])}), 'yyyy-MM-dd HH:mm')
ELSE
FORMAT(DATEADD(${String(fn(pt.arguments[2])).replace(/["']/g, '')},
+${fn(pt.arguments[1])}, ${fn(pt.arguments[0])}), 'yyyy-MM-dd')
END${colAlias}`
);
},
DATE_SUB: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
return knex.raw(
`CASE
WHEN ${fn(pt.arguments[0])} LIKE '%:%' THEN
FORMAT(DATEADD(${String(fn(pt.arguments[2])).replace(/["']/g, '')},
-${fn(pt.arguments[1])}.argument.value, ${fn(
pt.arguments[0]
)}), 'yyyy-MM-dd HH:mm')
ELSE
FORMAT(DATEADD(${String(fn(pt.arguments[2])).replace(/["']/g, '')},
-${fn(pt.arguments[1])}.argument.value, ${fn(
pt.arguments[0]
)}), 'yyyy-MM-dd')
${dateIN > 0 ? '+' : ''}${fn(pt.arguments[1])}, ${fn(pt.arguments[0])}), 'yyyy-MM-dd')
END${colAlias}`
);
}

16
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/mysql.ts

@ -37,7 +37,7 @@ const mysql2 = {
.raw(`CAST(${args.fn(args.pt.arguments[0])} as DOUBLE)${args.colAlias}`)
.wrap('(', ')');
},
DATE_ADD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
DATEADD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
return knex.raw(
`CASE
WHEN ${fn(pt.arguments[0])} LIKE '%:%' THEN
@ -54,20 +54,6 @@ const mysql2 = {
)}))
END${colAlias}`
);
},
DATE_SUB: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
return knex.raw(
`CASE
WHEN ${fn(pt.arguments[0])} LIKE '%:%' THEN
DATE_FORMAT(DATE_ADD(${fn(pt.arguments[0])}, INTERVAL
${fn(pt.arguments[1])}.argument.value
${String(fn(pt.arguments[2])).replace(/["']/g, '')}), '%Y-%m-%d %H:%i')
ELSE
DATE(DATE_ADD(${fn(pt.arguments[0])}, INTERVAL
${fn(pt.arguments[1])}.argument.value
${String(fn(pt.arguments[2])).replace(/["']/g, '')}))
END${colAlias}`
);
}
};

29
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/pg.ts

@ -33,37 +33,18 @@ const pg = {
.raw(`CAST(${fn(pt.arguments[0])} as DOUBLE PRECISION)${colAlias}`)
.wrap('(', ')');
},
DATE_ADD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
DATEADD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
return knex.raw(
`CASE
WHEN CAST(${fn(pt.arguments[0])} AS text) LIKE '%:%' THEN
to_char(${fn(pt.arguments[0])} + INTERVAL '${fn(pt.arguments[1])}
${fn(pt.arguments[0])} + INTERVAL '${fn(pt.arguments[1])}
${String(fn(pt.arguments[2])).replace(
/["']/g,
''
)}', 'YYYY-MM-DD HH24:MI')
)}'
ELSE
to_char(${fn(pt.arguments[0])} + INTERVAL '${fn(pt.arguments[1])}
${String(fn(pt.arguments[2])).replace(/["']/g, '')}', 'YYYY-MM-DD')
END${colAlias}`
);
},
DATE_SUB: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
return knex.raw(
`CASE
WHEN CAST(${fn(pt.arguments[0])} AS text) LIKE '%:%' THEN
to_char(${fn(pt.arguments[0])} - INTERVAL '${
fn(pt.arguments[1]).argument.value
}
${String(fn(pt.arguments[2])).replace(
/["']/g,
''
)}', 'YYYY-MM-DD HH24:MI')
ELSE
to_char(${fn(pt.arguments[0])} - INTERVAL '${
fn(pt.arguments[1]).argument.value
}
${String(fn(pt.arguments[2])).replace(/["']/g, '')}', 'YYYY-MM-DD')
${fn(pt.arguments[0])} + INTERVAL '${fn(pt.arguments[1])}
${String(fn(pt.arguments[2])).replace(/["']/g, '')}'
END${colAlias}`
);
}

25
packages/nocodb/src/lib/dataMapper/lib/sql/functionMappings/sqlite.ts

@ -56,43 +56,26 @@ const sqlite3 = {
.raw(`CAST(${args.fn(args.pt.arguments[0])} as FLOAT)${args.colAlias}`)
.wrap('(', ')');
},
DATE_ADD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
DATEADD: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
const dateIN = fn(pt.arguments[1]);
return knex.raw(
`CASE
WHEN ${fn(pt.arguments[0])} LIKE '%:%' THEN
STRFTIME('%Y-%m-%d %H:%M', DATETIME(DATETIME(${fn(
pt.arguments[0]
)}, 'localtime'),
'+${fn(pt.arguments[1])} ${String(fn(pt.arguments[2])).replace(
'${dateIN > 0 ? '+' : ''}${fn(pt.arguments[1])} ${String(fn(pt.arguments[2])).replace(
/["']/g,
''
)}'))
ELSE
DATE(DATETIME(${fn(pt.arguments[0])}, 'localtime'),
'+${fn(pt.arguments[1])} ${String(fn(pt.arguments[2])).replace(
'${dateIN > 0 ? '+' : ''}${fn(pt.arguments[1])} ${String(fn(pt.arguments[2])).replace(
/["']/g,
''
)}')
END${colAlias}`
);
},
DATE_SUB: ({ fn, knex, pt, colAlias }: MapFnArgs) => {
return knex.raw(
`CASE
WHEN ${fn(pt.arguments[0])} LIKE '%:%' THEN
STRFTIME('%Y-%m-%d %H:%M', DATETIME(DATETIME(${fn(
pt.arguments[0]
)}, 'localtime'),
'-${fn(pt.arguments[1]).argument.value} ${String(
fn(pt.arguments[2])
).replace(/["']/g, '')}'))
ELSE
DATE(DATETIME(${fn(pt.arguments[0])}, 'localtime'),
'-${fn(pt.arguments[1]).argument.value} ${String(
fn(pt.arguments[2])
).replace(/["']/g, '')}')
END${colAlias}`
);
}
};

Loading…
Cancel
Save