|
|
@ -8,6 +8,7 @@ import { XKnex } from '../../../index'; |
|
|
|
import LinkToAnotherRecordColumn from '../../../../../models/LinkToAnotherRecordColumn'; |
|
|
|
import LinkToAnotherRecordColumn from '../../../../../models/LinkToAnotherRecordColumn'; |
|
|
|
import LookupColumn from '../../../../../models/LookupColumn'; |
|
|
|
import LookupColumn from '../../../../../models/LookupColumn'; |
|
|
|
import { jsepCurlyHook, UITypes } from 'nocodb-sdk'; |
|
|
|
import { jsepCurlyHook, UITypes } from 'nocodb-sdk'; |
|
|
|
|
|
|
|
import { validateDateWithUnknownFormat } from '../helpers/formulaFnHelper'; |
|
|
|
|
|
|
|
|
|
|
|
// todo: switch function based on database
|
|
|
|
// todo: switch function based on database
|
|
|
|
|
|
|
|
|
|
|
@ -55,8 +56,11 @@ export default async function formulaQueryBuilderv2( |
|
|
|
jsep.plugins.register(jsepCurlyHook); |
|
|
|
jsep.plugins.register(jsepCurlyHook); |
|
|
|
const tree = jsep(_tree); |
|
|
|
const tree = jsep(_tree); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const columnIdToUidt = {}; |
|
|
|
|
|
|
|
|
|
|
|
// todo: improve - implement a common solution for filter, sort, formula, etc
|
|
|
|
// todo: improve - implement a common solution for filter, sort, formula, etc
|
|
|
|
for (const col of await model.getColumns()) { |
|
|
|
for (const col of await model.getColumns()) { |
|
|
|
|
|
|
|
columnIdToUidt[col.id] = col.uidt; |
|
|
|
if (col.id in aliasToColumn) continue; |
|
|
|
if (col.id in aliasToColumn) continue; |
|
|
|
switch (col.uidt) { |
|
|
|
switch (col.uidt) { |
|
|
|
case UITypes.Formula: |
|
|
|
case UITypes.Formula: |
|
|
@ -659,6 +663,47 @@ export default async function formulaQueryBuilderv2( |
|
|
|
const right = fn(pt.right, null, pt.operator).toQuery(); |
|
|
|
const right = fn(pt.right, null, pt.operator).toQuery(); |
|
|
|
let sql = `${left} ${pt.operator} ${right}${colAlias}`; |
|
|
|
let sql = `${left} ${pt.operator} ${right}${colAlias}`; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// comparing a date with empty string would throw
|
|
|
|
|
|
|
|
// `ERROR: zero-length delimited identifier` in Postgres
|
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
|
|
knex.clientType() === 'pg' && |
|
|
|
|
|
|
|
columnIdToUidt[pt.left.name] === UITypes.Date |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
// The correct way to compare with Date should be using
|
|
|
|
|
|
|
|
// `IS_AFTER`, `IS_BEFORE`, or `IS_SAME`
|
|
|
|
|
|
|
|
// This is to prevent empty data returned to UI due to incorrect SQL
|
|
|
|
|
|
|
|
if (pt.right.value === '') { |
|
|
|
|
|
|
|
if (pt.operator === '=') { |
|
|
|
|
|
|
|
sql = `${left} IS NULL ${colAlias}`; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
sql = `${left} IS NOT NULL ${colAlias}`; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (!validateDateWithUnknownFormat(pt.right.value)) { |
|
|
|
|
|
|
|
// left tree value is date but right tree value is not date
|
|
|
|
|
|
|
|
// return true if left tree value is not null, else false
|
|
|
|
|
|
|
|
sql = `${left} IS NOT NULL ${colAlias}`; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if ( |
|
|
|
|
|
|
|
knex.clientType() === 'pg' && |
|
|
|
|
|
|
|
columnIdToUidt[pt.right.name] === UITypes.Date |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
// The correct way to compare with Date should be using
|
|
|
|
|
|
|
|
// `IS_AFTER`, `IS_BEFORE`, or `IS_SAME`
|
|
|
|
|
|
|
|
// This is to prevent empty data returned to UI due to incorrect SQL
|
|
|
|
|
|
|
|
if (pt.left.value === '') { |
|
|
|
|
|
|
|
if (pt.operator === '=') { |
|
|
|
|
|
|
|
sql = `${right} IS NULL ${colAlias}`; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
sql = `${right} IS NOT NULL ${colAlias}`; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} else if (!validateDateWithUnknownFormat(pt.left.value)) { |
|
|
|
|
|
|
|
// right tree value is date but left tree value is not date
|
|
|
|
|
|
|
|
// return true if right tree value is not null, else false
|
|
|
|
|
|
|
|
sql = `${right} IS NOT NULL ${colAlias}`; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// handle NULL values when calling CONCAT for sqlite3
|
|
|
|
// handle NULL values when calling CONCAT for sqlite3
|
|
|
|
if (pt.left.fnName === 'CONCAT' && knex.clientType() === 'sqlite3') { |
|
|
|
if (pt.left.fnName === 'CONCAT' && knex.clientType() === 'sqlite3') { |
|
|
|
sql = `COALESCE(${left}, '') ${pt.operator} COALESCE(${right},'')${colAlias}`; |
|
|
|
sql = `COALESCE(${left}, '') ${pt.operator} COALESCE(${right},'')${colAlias}`; |
|
|
|