From 046a1f63b1dec438f7f22c85159aefd96c824774 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 1 Jul 2022 11:22:55 +0800 Subject: [PATCH 1/9] fix: lint --- .../db/sql-data-mapper/lib/sql/conditionV2.ts | 53 +++++++++---------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index 67ad3ca1f7..b6fe2ea109 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -50,11 +50,11 @@ const parseConditionV2 = async ( } if (Array.isArray(_filter)) { const qbs = await Promise.all( - _filter.map(child => parseConditionV2(child, knex, aliasCount)) + _filter.map((child) => parseConditionV2(child, knex, aliasCount)) ); - return qbP => { - qbP.where(qb => { + return (qbP) => { + qbP.where((qb) => { for (const [i, qb1] of Object.entries(qbs)) { qb[getLogicalOpMethod(_filter[i])](qb1); } @@ -64,11 +64,11 @@ const parseConditionV2 = async ( const children = await filter.getChildren(); const qbs = await Promise.all( - (children || []).map(child => parseConditionV2(child, knex, aliasCount)) + (children || []).map((child) => parseConditionV2(child, knex, aliasCount)) ); - return qbP => { - qbP[getLogicalOpMethod(filter)](qb => { + return (qbP) => { + qbP[getLogicalOpMethod(filter)]((qb) => { for (const [i, qb1] of Object.entries(qbs)) { qb[getLogicalOpMethod(children[i])](qb1); } @@ -78,7 +78,8 @@ const parseConditionV2 = async ( const column = await filter.getColumn(); if (!column) return () => {}; if (column.uidt === UITypes.LinkToAnotherRecord) { - const colOptions = (await column.getColOptions()) as LinkToAnotherRecordColumn; + const colOptions = + (await column.getColOptions()) as LinkToAnotherRecordColumn; const childColumn = await colOptions.getChildColumn(); const parentColumn = await colOptions.getParentColumn(); const childModel = await childColumn.getModel(); @@ -97,7 +98,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: childModel.id, - fk_column_id: childModel?.primaryValue?.id + fk_column_id: childModel?.primaryValue?.id, }), knex, aliasCount @@ -121,7 +122,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id + fk_column_id: parentModel?.primaryValue?.id, }), knex, aliasCount @@ -153,7 +154,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id + fk_column_id: parentModel?.primaryValue?.id, }), knex, aliasCount @@ -167,7 +168,7 @@ const parseConditionV2 = async ( }; } - return _qb => {}; + return (_qb) => {}; } else if (column.uidt === UITypes.Lookup) { return await generateLookupCondition(column, filter, knex, aliasCount); } else if (column.uidt === UITypes.Rollup && !customWhereClause) { @@ -175,7 +176,7 @@ const parseConditionV2 = async ( await genRollupSelectv2({ knex, alias, - columnOptions: (await column.getColOptions()) as RollupColumn + columnOptions: (await column.getColOptions()) as RollupColumn, }) ).builder; return parseConditionV2( @@ -213,7 +214,7 @@ const parseConditionV2 = async ( ); let val = customWhereClause ? customWhereClause : filter.value; - return qb => { + return (qb) => { switch (filter.comparison_op) { case 'eq': qb = qb.where(field, val); @@ -321,7 +322,7 @@ const parseConditionV2 = async ( const negatedMapping = { nlike: { comparison_op: 'like' }, - neq: { comparison_op: 'eq' } + neq: { comparison_op: 'eq' }, }; function getAlias(aliasCount: { count: number }) { @@ -337,9 +338,8 @@ async function generateLookupCondition( ): Promise { const colOptions = await col.getColOptions(); const relationColumn = await colOptions.getRelationColumn(); - const relationColumnOptions = await relationColumn.getColOptions< - LinkToAnotherRecordColumn - >(); + const relationColumnOptions = + await relationColumn.getColOptions(); // const relationModel = await relationColumn.getModel(); const lookupColumn = await colOptions.getLookupColumn(); const alias = getAlias(aliasCount); @@ -362,7 +362,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}) + : {}), }, lookupColumn, qb, @@ -385,7 +385,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}) + : {}), }, lookupColumn, qb, @@ -419,7 +419,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}) + : {}), }, lookupColumn, qb, @@ -455,9 +455,8 @@ async function nestedConditionJoin( await lookupColumn.getColOptions() ).getRelationColumn() : lookupColumn; - const relationColOptions = await relationColumn.getColOptions< - LinkToAnotherRecordColumn - >(); + const relationColOptions = + await relationColumn.getColOptions(); const relAlias = `__nc${aliasCount.count++}`; const childColumn = await relationColOptions.getChildColumn(); @@ -528,7 +527,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: childModel.id, - fk_column_id: childModel.primaryValue?.id + fk_column_id: childModel.primaryValue?.id, }), knex, aliasCount, @@ -544,7 +543,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id + fk_column_id: parentModel?.primaryValue?.id, }), knex, aliasCount, @@ -560,7 +559,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: parentModel.id, - fk_column_id: parentModel.primaryValue?.id + fk_column_id: parentModel.primaryValue?.id, }), knex, aliasCount, @@ -577,7 +576,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: (await lookupColumn.getModel()).id, - fk_column_id: lookupColumn?.id + fk_column_id: lookupColumn?.id, }), knex, aliasCount, From 671ad68171d0d899a3758acd51af9b458c4eba60 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 1 Jul 2022 14:02:21 +0800 Subject: [PATCH 2/9] fix: sanitise / unsanitise strings only --- .../src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts index a98be3b9e7..15b309fb63 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/helpers/sanitize.ts @@ -1,9 +1,11 @@ export function sanitize(v) { + if (typeof v !== 'string') return v; return v?.replace(/([^\\]|^)(\?+)/g, (_, m1, m2) => { return `${m1}${m2.split('?').join('\\?')}`; }); } export function unsanitize(v) { + if (typeof v !== 'string') return v; return v?.replace(/\\[?]/g, '?'); } From 44d25523fa24d5b648dea4cfcc01a8579272fe47 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 1 Jul 2022 14:29:42 +0800 Subject: [PATCH 3/9] fix: handle null & not null for filter on bt cells --- .../src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index b6fe2ea109..dc617c2ca1 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -111,6 +111,17 @@ const parseConditionV2 = async ( else qbP.whereIn(parentColumn.column_name, selectQb); }; } else if (colOptions.type === RelationTypes.BELONGS_TO) { + if (filter.comparison_op === 'null') { + return (qb) => { + qb.whereNull(childColumn.column_name); + }; + } + if (filter.comparison_op === 'notnull') { + return (qb) => { + qb.whereNotNull(childColumn.column_name); + }; + } + const selectQb = knex(parentModel.table_name).select( parentColumn.column_name ); From 8c082d42592b26ea04c81cf82b02f3fec6ec6f38 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 1 Jul 2022 15:08:29 +0800 Subject: [PATCH 4/9] fix: revise filterComparisonOp for mm, hm & bt --- .../spreadsheet/components/ColumnFilter.vue | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue b/packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue index f5b4007fa1..5ebafbfeda 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue @@ -324,13 +324,23 @@ export default { if ( f && f.fk_column_id && - this.columnsById[f.fk_column_id] && - this.columnsById[f.fk_column_id].uidt === - UITypes.LinkToAnotherRecord && - this.columnsById[f.fk_column_id].uidt === UITypes.Lookup + this.columnsById[f.fk_column_id] ) { - return !['notempty', 'empty', 'notnull', 'null'].includes(op.value) - } + const uidt = this.columnsById[f.fk_column_id].uidt + if (uidt === UITypes.Lookup) { + // TODO: handle it later + return !['notempty', 'empty', 'notnull', 'null'].includes(op.value) + } else if (uidt === UITypes.LinkToAnotherRecord) { + const type = this.columnsById[f.fk_column_id].colOptions.type + if (type === 'hm' || type === 'mm') { + // exclude notnull & null + return !['notnull', 'null'].includes(op.value) + } else if (type === 'bt') { + // exclude notempty & empty + return !['notempty', 'empty'].includes(op.value) + } + } + } return true }) }, From 7415f7f584d100782380958937a07878d194ceda Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 1 Jul 2022 19:45:11 +0800 Subject: [PATCH 5/9] wip: handle empty & not empty for hm --- .../db/sql-data-mapper/lib/sql/conditionV2.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index dc617c2ca1..49ea65bd16 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -87,6 +87,31 @@ const parseConditionV2 = async ( const parentModel = await parentColumn.getModel(); await parentModel.getColumns(); if (colOptions.type === RelationTypes.HAS_MANY) { + if ( + filter.comparison_op === 'empty' || + filter.comparison_op === 'notempty' + ) { + const selectParentQb = knex(parentModel.table_name); + console.log('HERE1'); + console.log(selectParentQb.toQuery()); + + const selectHmCount = knex(childModel.table_name) + .select(childColumn.column_name) + .count(childColumn.column_name) + .whereNotNull(childColumn.column_name) + .groupBy(childColumn.column_name); + console.log('HERE2'); + console.log(selectHmCount.toQuery()); + + const q = selectParentQb.leftJoin( + selectHmCount.as('t2'), + parentModel.table_name + '.' + parentColumn.column_name, + 't2.' + childColumn.column_name + ); + console.log('HERE3'); + console.log(q.toQuery()); + return q; + } const selectQb = knex(childModel.table_name).select( childColumn.column_name ); From 8dec49015ecc8f558a0152e643f430da555fc816 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Fri, 1 Jul 2022 17:28:17 +0530 Subject: [PATCH 6/9] wip: nested filter empty/not empty Signed-off-by: Pranav C --- .../db/sql-data-mapper/lib/sql/conditionV2.ts | 96 +++++++++++-------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index 49ea65bd16..00602e5c91 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -50,11 +50,11 @@ const parseConditionV2 = async ( } if (Array.isArray(_filter)) { const qbs = await Promise.all( - _filter.map((child) => parseConditionV2(child, knex, aliasCount)) + _filter.map(child => parseConditionV2(child, knex, aliasCount)) ); - return (qbP) => { - qbP.where((qb) => { + return qbP => { + qbP.where(qb => { for (const [i, qb1] of Object.entries(qbs)) { qb[getLogicalOpMethod(_filter[i])](qb1); } @@ -64,11 +64,11 @@ const parseConditionV2 = async ( const children = await filter.getChildren(); const qbs = await Promise.all( - (children || []).map((child) => parseConditionV2(child, knex, aliasCount)) + (children || []).map(child => parseConditionV2(child, knex, aliasCount)) ); - return (qbP) => { - qbP[getLogicalOpMethod(filter)]((qb) => { + return qbP => { + qbP[getLogicalOpMethod(filter)](qb => { for (const [i, qb1] of Object.entries(qbs)) { qb[getLogicalOpMethod(children[i])](qb1); } @@ -78,8 +78,7 @@ const parseConditionV2 = async ( const column = await filter.getColumn(); if (!column) return () => {}; if (column.uidt === UITypes.LinkToAnotherRecord) { - const colOptions = - (await column.getColOptions()) as LinkToAnotherRecordColumn; + const colOptions = (await column.getColOptions()) as LinkToAnotherRecordColumn; const childColumn = await colOptions.getChildColumn(); const parentColumn = await colOptions.getParentColumn(); const childModel = await childColumn.getModel(); @@ -96,21 +95,32 @@ const parseConditionV2 = async ( console.log(selectParentQb.toQuery()); const selectHmCount = knex(childModel.table_name) - .select(childColumn.column_name) .count(childColumn.column_name) - .whereNotNull(childColumn.column_name) - .groupBy(childColumn.column_name); - console.log('HERE2'); - console.log(selectHmCount.toQuery()); - - const q = selectParentQb.leftJoin( - selectHmCount.as('t2'), - parentModel.table_name + '.' + parentColumn.column_name, - 't2.' + childColumn.column_name - ); - console.log('HERE3'); - console.log(q.toQuery()); - return q; + .where( + childColumn.column_name, + knex.raw('??.??', [ + alias || parentModel.table_name, + parentColumn.column_name + ]) + ); + + // console.log('HERE2'); + // console.log(selectHmCount.toQuery()); + // + // const q = selectParentQb.leftJoin( + // selectHmCount.as('t2'), + // parentModel.table_name + '.' + parentColumn.column_name, + // 't2.' + childColumn.column_name + // ); + // console.log('HERE3'); + // console.log(q.toQuery()); + return qb => { + if (filter.comparison_op === 'empty') { + qb.where(knex.raw('0'), selectHmCount); + } else { + qb.whereNot(knex.raw('0'), selectHmCount); + } + }; } const selectQb = knex(childModel.table_name).select( childColumn.column_name @@ -123,7 +133,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: childModel.id, - fk_column_id: childModel?.primaryValue?.id, + fk_column_id: childModel?.primaryValue?.id }), knex, aliasCount @@ -137,12 +147,12 @@ const parseConditionV2 = async ( }; } else if (colOptions.type === RelationTypes.BELONGS_TO) { if (filter.comparison_op === 'null') { - return (qb) => { + return qb => { qb.whereNull(childColumn.column_name); }; } if (filter.comparison_op === 'notnull') { - return (qb) => { + return qb => { qb.whereNotNull(childColumn.column_name); }; } @@ -158,7 +168,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id, + fk_column_id: parentModel?.primaryValue?.id }), knex, aliasCount @@ -190,7 +200,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id, + fk_column_id: parentModel?.primaryValue?.id }), knex, aliasCount @@ -204,7 +214,7 @@ const parseConditionV2 = async ( }; } - return (_qb) => {}; + return _qb => {}; } else if (column.uidt === UITypes.Lookup) { return await generateLookupCondition(column, filter, knex, aliasCount); } else if (column.uidt === UITypes.Rollup && !customWhereClause) { @@ -212,7 +222,7 @@ const parseConditionV2 = async ( await genRollupSelectv2({ knex, alias, - columnOptions: (await column.getColOptions()) as RollupColumn, + columnOptions: (await column.getColOptions()) as RollupColumn }) ).builder; return parseConditionV2( @@ -250,7 +260,7 @@ const parseConditionV2 = async ( ); let val = customWhereClause ? customWhereClause : filter.value; - return (qb) => { + return qb => { switch (filter.comparison_op) { case 'eq': qb = qb.where(field, val); @@ -358,7 +368,7 @@ const parseConditionV2 = async ( const negatedMapping = { nlike: { comparison_op: 'like' }, - neq: { comparison_op: 'eq' }, + neq: { comparison_op: 'eq' } }; function getAlias(aliasCount: { count: number }) { @@ -374,8 +384,9 @@ async function generateLookupCondition( ): Promise { const colOptions = await col.getColOptions(); const relationColumn = await colOptions.getRelationColumn(); - const relationColumnOptions = - await relationColumn.getColOptions(); + const relationColumnOptions = await relationColumn.getColOptions< + LinkToAnotherRecordColumn + >(); // const relationModel = await relationColumn.getModel(); const lookupColumn = await colOptions.getLookupColumn(); const alias = getAlias(aliasCount); @@ -398,7 +409,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}), + : {}) }, lookupColumn, qb, @@ -421,7 +432,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}), + : {}) }, lookupColumn, qb, @@ -455,7 +466,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}), + : {}) }, lookupColumn, qb, @@ -491,8 +502,9 @@ async function nestedConditionJoin( await lookupColumn.getColOptions() ).getRelationColumn() : lookupColumn; - const relationColOptions = - await relationColumn.getColOptions(); + const relationColOptions = await relationColumn.getColOptions< + LinkToAnotherRecordColumn + >(); const relAlias = `__nc${aliasCount.count++}`; const childColumn = await relationColOptions.getChildColumn(); @@ -563,7 +575,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: childModel.id, - fk_column_id: childModel.primaryValue?.id, + fk_column_id: childModel.primaryValue?.id }), knex, aliasCount, @@ -579,7 +591,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id, + fk_column_id: parentModel?.primaryValue?.id }), knex, aliasCount, @@ -595,7 +607,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: parentModel.id, - fk_column_id: parentModel.primaryValue?.id, + fk_column_id: parentModel.primaryValue?.id }), knex, aliasCount, @@ -612,7 +624,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: (await lookupColumn.getModel()).id, - fk_column_id: lookupColumn?.id, + fk_column_id: lookupColumn?.id }), knex, aliasCount, From 1d5d11d80af32260fa07b7a8b1f9d73d176904de Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Fri, 1 Jul 2022 20:00:10 +0800 Subject: [PATCH 7/9] chore: clean up --- .../db/sql-data-mapper/lib/sql/conditionV2.ts | 75 ++++++++----------- 1 file changed, 30 insertions(+), 45 deletions(-) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index 00602e5c91..ab9bb91b2a 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -50,11 +50,11 @@ const parseConditionV2 = async ( } if (Array.isArray(_filter)) { const qbs = await Promise.all( - _filter.map(child => parseConditionV2(child, knex, aliasCount)) + _filter.map((child) => parseConditionV2(child, knex, aliasCount)) ); - return qbP => { - qbP.where(qb => { + return (qbP) => { + qbP.where((qb) => { for (const [i, qb1] of Object.entries(qbs)) { qb[getLogicalOpMethod(_filter[i])](qb1); } @@ -64,11 +64,11 @@ const parseConditionV2 = async ( const children = await filter.getChildren(); const qbs = await Promise.all( - (children || []).map(child => parseConditionV2(child, knex, aliasCount)) + (children || []).map((child) => parseConditionV2(child, knex, aliasCount)) ); - return qbP => { - qbP[getLogicalOpMethod(filter)](qb => { + return (qbP) => { + qbP[getLogicalOpMethod(filter)]((qb) => { for (const [i, qb1] of Object.entries(qbs)) { qb[getLogicalOpMethod(children[i])](qb1); } @@ -78,7 +78,8 @@ const parseConditionV2 = async ( const column = await filter.getColumn(); if (!column) return () => {}; if (column.uidt === UITypes.LinkToAnotherRecord) { - const colOptions = (await column.getColOptions()) as LinkToAnotherRecordColumn; + const colOptions = + (await column.getColOptions()) as LinkToAnotherRecordColumn; const childColumn = await colOptions.getChildColumn(); const parentColumn = await colOptions.getParentColumn(); const childModel = await childColumn.getModel(); @@ -90,31 +91,17 @@ const parseConditionV2 = async ( filter.comparison_op === 'empty' || filter.comparison_op === 'notempty' ) { - const selectParentQb = knex(parentModel.table_name); - console.log('HERE1'); - console.log(selectParentQb.toQuery()); - const selectHmCount = knex(childModel.table_name) .count(childColumn.column_name) .where( childColumn.column_name, knex.raw('??.??', [ alias || parentModel.table_name, - parentColumn.column_name + parentColumn.column_name, ]) ); - // console.log('HERE2'); - // console.log(selectHmCount.toQuery()); - // - // const q = selectParentQb.leftJoin( - // selectHmCount.as('t2'), - // parentModel.table_name + '.' + parentColumn.column_name, - // 't2.' + childColumn.column_name - // ); - // console.log('HERE3'); - // console.log(q.toQuery()); - return qb => { + return (qb) => { if (filter.comparison_op === 'empty') { qb.where(knex.raw('0'), selectHmCount); } else { @@ -133,7 +120,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: childModel.id, - fk_column_id: childModel?.primaryValue?.id + fk_column_id: childModel?.primaryValue?.id, }), knex, aliasCount @@ -147,12 +134,12 @@ const parseConditionV2 = async ( }; } else if (colOptions.type === RelationTypes.BELONGS_TO) { if (filter.comparison_op === 'null') { - return qb => { + return (qb) => { qb.whereNull(childColumn.column_name); }; } if (filter.comparison_op === 'notnull') { - return qb => { + return (qb) => { qb.whereNotNull(childColumn.column_name); }; } @@ -168,7 +155,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id + fk_column_id: parentModel?.primaryValue?.id, }), knex, aliasCount @@ -200,7 +187,7 @@ const parseConditionV2 = async ( ? negatedMapping[filter.comparison_op] : {}), fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id + fk_column_id: parentModel?.primaryValue?.id, }), knex, aliasCount @@ -214,7 +201,7 @@ const parseConditionV2 = async ( }; } - return _qb => {}; + return (_qb) => {}; } else if (column.uidt === UITypes.Lookup) { return await generateLookupCondition(column, filter, knex, aliasCount); } else if (column.uidt === UITypes.Rollup && !customWhereClause) { @@ -222,7 +209,7 @@ const parseConditionV2 = async ( await genRollupSelectv2({ knex, alias, - columnOptions: (await column.getColOptions()) as RollupColumn + columnOptions: (await column.getColOptions()) as RollupColumn, }) ).builder; return parseConditionV2( @@ -260,7 +247,7 @@ const parseConditionV2 = async ( ); let val = customWhereClause ? customWhereClause : filter.value; - return qb => { + return (qb) => { switch (filter.comparison_op) { case 'eq': qb = qb.where(field, val); @@ -368,7 +355,7 @@ const parseConditionV2 = async ( const negatedMapping = { nlike: { comparison_op: 'like' }, - neq: { comparison_op: 'eq' } + neq: { comparison_op: 'eq' }, }; function getAlias(aliasCount: { count: number }) { @@ -384,9 +371,8 @@ async function generateLookupCondition( ): Promise { const colOptions = await col.getColOptions(); const relationColumn = await colOptions.getRelationColumn(); - const relationColumnOptions = await relationColumn.getColOptions< - LinkToAnotherRecordColumn - >(); + const relationColumnOptions = + await relationColumn.getColOptions(); // const relationModel = await relationColumn.getModel(); const lookupColumn = await colOptions.getLookupColumn(); const alias = getAlias(aliasCount); @@ -409,7 +395,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}) + : {}), }, lookupColumn, qb, @@ -432,7 +418,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}) + : {}), }, lookupColumn, qb, @@ -466,7 +452,7 @@ async function generateLookupCondition( ...filter, ...(filter.comparison_op in negatedMapping ? negatedMapping[filter.comparison_op] - : {}) + : {}), }, lookupColumn, qb, @@ -502,9 +488,8 @@ async function nestedConditionJoin( await lookupColumn.getColOptions() ).getRelationColumn() : lookupColumn; - const relationColOptions = await relationColumn.getColOptions< - LinkToAnotherRecordColumn - >(); + const relationColOptions = + await relationColumn.getColOptions(); const relAlias = `__nc${aliasCount.count++}`; const childColumn = await relationColOptions.getChildColumn(); @@ -575,7 +560,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: childModel.id, - fk_column_id: childModel.primaryValue?.id + fk_column_id: childModel.primaryValue?.id, }), knex, aliasCount, @@ -591,7 +576,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: parentModel.id, - fk_column_id: parentModel?.primaryValue?.id + fk_column_id: parentModel?.primaryValue?.id, }), knex, aliasCount, @@ -607,7 +592,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: parentModel.id, - fk_column_id: parentModel.primaryValue?.id + fk_column_id: parentModel.primaryValue?.id, }), knex, aliasCount, @@ -624,7 +609,7 @@ async function nestedConditionJoin( new Filter({ ...filter, fk_model_id: (await lookupColumn.getModel()).id, - fk_column_id: lookupColumn?.id + fk_column_id: lookupColumn?.id, }), knex, aliasCount, From dcba839499023831b66ae5a797be90f92d765dce Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 2 Jul 2022 13:22:13 +0800 Subject: [PATCH 8/9] fix: handle empty & notempty for mm case --- .../db/sql-data-mapper/lib/sql/conditionV2.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts index ab9bb91b2a..cbd810af3f 100644 --- a/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts +++ b/packages/nocodb/src/lib/db/sql-data-mapper/lib/sql/conditionV2.ts @@ -172,6 +172,29 @@ const parseConditionV2 = async ( const mmParentColumn = await colOptions.getMMParentColumn(); const mmChildColumn = await colOptions.getMMChildColumn(); + if ( + filter.comparison_op === 'empty' || + filter.comparison_op === 'notempty' + ) { + const selectMmCount = knex(mmModel.table_name) + .count(mmChildColumn.column_name) + .where( + mmChildColumn.column_name, + knex.raw('??.??', [ + alias || childModel.table_name, + childColumn.column_name, + ]) + ); + + return (qb) => { + if (filter.comparison_op === 'empty') { + qb.where(knex.raw('0'), selectMmCount); + } else { + qb.whereNot(knex.raw('0'), selectMmCount); + } + }; + } + const selectQb = knex(mmModel.table_name) .select(mmChildColumn.column_name) .join( From 938290c2d598b6b8ca87cce419cc2d5695d9d9c9 Mon Sep 17 00:00:00 2001 From: Wing-Kam Wong Date: Sat, 2 Jul 2022 13:40:54 +0800 Subject: [PATCH 9/9] fix: revise filter operation & value display logic --- .../components/project/spreadsheet/components/ColumnFilter.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue b/packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue index 5ebafbfeda..32b8f26604 100644 --- a/packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue +++ b/packages/nc-gui/components/project/spreadsheet/components/ColumnFilter.vue @@ -108,6 +108,7 @@ class="flex-shrink-1 flex-grow-0 caption nc-filter-operation-select" :items="filterComparisonOp(filter)" :placeholder="$t('labels.operation')" + v-show="filter && filter.fk_column_id" solo flat style="max-width: 120px" @@ -142,6 +143,7 @@ v-else :key="i + '_7'" v-model="filter.value" + v-show="filter && filter.fk_column_id" solo flat hide-details