diff --git a/packages/nc-gui/components/smartsheet/toolbar/FilterInput.vue b/packages/nc-gui/components/smartsheet/toolbar/FilterInput.vue index e4e4c2267e..95b4b3dc16 100644 --- a/packages/nc-gui/components/smartsheet/toolbar/FilterInput.vue +++ b/packages/nc-gui/components/smartsheet/toolbar/FilterInput.vue @@ -115,18 +115,28 @@ const booleanOptions = [ { value: null, label: 'unset' }, ] +const renderSingleSelect = (op: string) => { + // use MultiSelect for SingleSelect columns for anyof / nanyof filters + if (['anyof', 'nanyof'].includes(op)) { + return MultiSelect + } + return SingleSelect +} + +const renderDateFilterInput = (sub_op: string) => { + if (['daysAgo', 'daysFromNow', 'pastNumberOfDays', 'nextNumberOfDays'].includes(sub_op)) { + return Decimal + } + return DatePicker +} + const componentMap: Partial> = $computed(() => { return { - // use MultiSelect for SingleSelect columns for anyof / nanyof filters - isSingleSelect: ['anyof', 'nanyof'].includes(props.filter.comparison_op!) ? MultiSelect : SingleSelect, + isSingleSelect: renderSingleSelect(props.filter.comparison_op!), isMultiSelect: MultiSelect, - isDate: ['daysAgo', 'daysFromNow', 'pastNumberOfDays', 'nextNumberOfDays'].includes(props.filter.comparison_sub_op!) - ? Decimal - : DatePicker, + isDate: renderDateFilterInput(props.filter.comparison_sub_op!), isYear: YearPicker, - isDateTime: ['daysAgo', 'daysFromNow', 'pastNumberOfDays', 'nextNumberOfDays'].includes(props.filter.comparison_sub_op!) - ? Decimal - : DateTimePicker, + isDateTime: renderDateFilterInput(props.filter.comparison_sub_op!), isTime: TimePicker, isRating: Rating, isDuration: Duration, 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 fd2403bf22..08435dd0bd 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 @@ -5,6 +5,7 @@ import Filter from '../../../../models/Filter'; import genRollupSelectv2 from './genRollupSelectv2'; import formulaQueryBuilderv2 from './formulav2/formulaQueryBuilderv2'; import { sanitize } from './helpers/sanitize'; +import { convertDateFormatByType } from './helpers/formulaFnHelper'; import type LinkToAnotherRecordColumn from '../../../../models/LinkToAnotherRecordColumn'; import type { Knex } from 'knex'; import type { XKnex } from '../../index'; @@ -321,8 +322,8 @@ const parseConditionV2 = async ( const dateFormat = qb?.client?.config?.client === 'mysql2' - ? 'YYYY-MM-DD HH:mm:ss' - : 'YYYY-MM-DD HH:mm:ssZ'; + ? 'YYYY-MM-DD HH:mm' + : 'YYYY-MM-DD HH:mmZ'; if ([UITypes.Date, UITypes.DateTime].includes(column.uidt)) { const now = dayjs(new Date()); @@ -404,6 +405,19 @@ const parseConditionV2 = async ( switch (filter.comparison_op) { case 'eq': + if (column.uidt === UITypes.DateTime) { + // for filter with input (exactDate), we only match the date + qb = qb.whereRaw( + `${convertDateFormatByType( + field, + qb?.client?.config?.client, + column.meta.date_format + )} = ?`, + [val.substring(0, 10)] + ); + break; + } + if (qb?.client?.config?.client === 'mysql2') { if ( [ @@ -431,6 +445,19 @@ const parseConditionV2 = async ( break; case 'neq': case 'not': + if (column.uidt === UITypes.DateTime) { + // for filter with input (exactDate), we only match the date + qb = qb.whereRaw( + `${convertDateFormatByType( + field, + qb?.client?.config?.client, + column.meta.date_format + )} != ?`, + [val.substring(0, 10)] + ); + break; + } + if (qb?.client?.config?.client === 'mysql2') { if ( [ 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 5a21ba3261..6e71ba9df1 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 @@ -54,6 +54,25 @@ export function validateDateWithUnknownFormat(v: string) { return false; } +export function convertDateFormatByType(query, clientType, dateFormat) { + if (clientType === 'mysql2') { + query = `DATE_FORMAT(${query}, '${convertDateFormat( + dateFormat, + clientType + )}')`; + } else if (clientType === 'pg') { + query = `TO_CHAR(${query}, '${convertDateFormat(dateFormat, clientType)}')`; + } else if (clientType === 'sqlite3') { + query = `strftime('${convertDateFormat( + dateFormat, + clientType + )}', ${query})`; + } else if (clientType === 'mssql') { + query = `FORMAT(${query}, '${convertDateFormat(dateFormat, clientType)}')`; + } + return query; +} + export async function convertDateFormatForConcat( o, columnIdToUidt, @@ -71,27 +90,7 @@ export async function convertDateFormatForConcat( }) ).meta; - if (clientType === 'mysql2') { - query = `DATE_FORMAT(${query}, '${convertDateFormat( - meta.date_format, - clientType - )}')`; - } else if (clientType === 'pg') { - query = `TO_CHAR(${query}, '${convertDateFormat( - meta.date_format, - clientType - )}')`; - } else if (clientType === 'sqlite3') { - query = `strftime('${convertDateFormat( - meta.date_format, - clientType - )}', ${query})`; - } else if (clientType === 'mssql') { - query = `FORMAT(${query}, '${convertDateFormat( - meta.date_format, - clientType - )}')`; - } + return convertDateFormatByType(query, clientType, meta.date_format); } return query; }