From da4c052f8a642707f8bf635d792b84e6ed8e4ea5 Mon Sep 17 00:00:00 2001 From: teable-bot Date: Mon, 2 Mar 2026 04:30:14 +0000 Subject: [PATCH] [sync] fix: invite link item style (#1320) Synced from teableio/teable-ee@8383bb6 --- apps/nestjs-backend/package.json | 26 +- .../base-import-attachments.processor.ts | 170 +- .../export/metrics/export-metrics.module.ts | 5 +- .../export/metrics/export-metrics.service.ts | 10 +- .../export/metrics/export-tracing.service.ts | 11 + .../open-api/export-open-api.service.ts | 6 +- .../src/features/field/model/factory.spec.ts | 54 + .../src/features/field/model/factory.ts | 72 +- .../field-open-api-v2.service.spec.ts | 605 ++++- .../open-api/field-open-api-v2.service.ts | 661 ++++- .../open-api/field-open-api.controller.ts | 28 + .../field/open-api/field-open-api.service.ts | 12 +- .../import/metrics/import-metrics.module.ts | 5 +- .../import/metrics/import-metrics.service.ts | 12 - .../import/metrics/import-tracing.service.ts | 11 + .../open-api/import-csv-chunk.processor.ts | 6 +- .../open-api/record-open-api-v2.service.ts | 10 +- .../record-modify/record-update.service.ts | 7 +- .../features/selection/selection.service.ts | 5 +- .../operations/paste-selection.operation.ts | 14 +- .../src/features/v2/v2-undo-redo.service.ts | 151 +- apps/nestjs-backend/src/tracing.ts | 37 +- .../src/tracing/base-tracing.service.ts | 17 + .../src/types/i18n.generated.ts | 1 + .../test/field-duplicate.e2e-spec.ts | 142 ++ apps/nestjs-backend/test/formula.e2e-spec.ts | 2 +- .../nestjs-backend/test/integrity.e2e-spec.ts | 3 - apps/nestjs-backend/test/lookup.e2e-spec.ts | 1 - .../test/utils/event-promise.ts | 12 +- .../blocks/table/table-header/TableHeader.tsx | 23 +- .../components/InviteLinkItem.tsx | 69 +- packages/common-i18n/src/locales/de/sdk.json | 2 +- .../common-i18n/src/locales/en/common.json | 1 + packages/common-i18n/src/locales/en/sdk.json | 2 +- packages/common-i18n/src/locales/es/sdk.json | 2 +- packages/common-i18n/src/locales/fr/sdk.json | 2 +- packages/common-i18n/src/locales/it/sdk.json | 2 +- packages/common-i18n/src/locales/ja/sdk.json | 2 +- packages/common-i18n/src/locales/ru/sdk.json | 2 +- packages/common-i18n/src/locales/tr/sdk.json | 2 +- packages/common-i18n/src/locales/uk/sdk.json | 2 +- .../common-i18n/src/locales/zh/common.json | 1 + packages/common-i18n/src/locales/zh/sdk.json | 2 +- .../core/src/errors/extract-error-message.ts | 58 + packages/core/src/errors/index.ts | 1 + .../openapi/src/admin/setting/ai-key-stats.ts | 53 + packages/openapi/src/admin/setting/index.ts | 1 + packages/openapi/src/admin/setting/update.ts | 47 + .../PostgresTableRepository.spec.ts | 71 + .../repositories/PostgresTableRepository.ts | 30 +- .../TableFieldPersistenceBuilder.ts | 27 +- .../TableRecordConditionWhereVisitor.spec.ts | 18 + .../TableRecordConditionWhereVisitor.ts | 12 +- .../computed/ComputedFieldBackfillService.ts | 2 + .../record/computed/ComputedFieldUpdater.ts | 1 + .../record/computed/ComputedUpdatePlanner.ts | 7 +- .../computed/UpdateFromSelectBuilder.ts | 52 +- .../TableRecordQueryBuilderManager.ts | 2 +- .../ComputedFieldSelectExpressionVisitor.ts | 7 +- .../ComputedTableRecordQueryBuilder.spec.ts | 83 +- .../ComputedTableRecordQueryBuilder.ts | 91 +- .../TableRecordConditionWhereVisitor.spec.ts | 42 +- .../TableRecordConditionWhereVisitor.ts | 62 +- .../FieldValueChangeCollectorVisitor.ts | 5 +- .../visitors/TableSchemaUpdateVisitor.ts | 29 +- .../TableSchemaUpdateVisitor.spec.ts | 88 +- .../src/handlers/tables/duplicateField.ts | 52 + .../src/handlers/tables/index.ts | 1 + .../src/router.ts | 30 + packages/v2/contract-http/src/contract.ts | 13 + packages/v2/contract-http/src/index.ts | 1 + packages/v2/contract-http/src/table/dto.ts | 18 +- .../contract-http/src/table/duplicateField.ts | 59 + .../src/table/mapTableDtoToDomain.ts | 13 +- .../src/commands/CreateFieldCommand.spec.ts | 95 + .../core/src/commands/CreateFieldCommand.ts | 25 +- .../src/commands/CreateFieldHandler.spec.ts | 272 ++ .../core/src/commands/CreateFieldHandler.ts | 63 +- .../src/commands/CreateTablesHandler.spec.ts | 107 +- .../core/src/commands/CreateTablesHandler.ts | 3 +- .../commands/DuplicateFieldCommand.spec.ts | 2 + .../src/commands/DuplicateFieldCommand.ts | 37 +- .../src/commands/DuplicateFieldHandler.ts | 24 +- .../v2/core/src/commands/FieldValidation.ts | 1 - .../core/src/commands/TableFieldSpecs.spec.ts | 64 + .../v2/core/src/commands/TableFieldSpecs.ts | 122 +- .../src/commands/TableFieldUpdateSpecs.ts | 36 + .../v2/core/src/domain/formula/visitor.ts | 24 +- .../v2/core/src/domain/table/Table.spec.ts | 203 +- packages/v2/core/src/domain/table/Table.ts | 43 +- .../v2/core/src/domain/table/TableMutator.ts | 143 +- .../src/domain/table/events/FieldCreated.ts | 12 +- .../v2/core/src/domain/table/fields/Field.ts | 27 +- .../src/domain/table/fields/FieldFactory.ts | 4 + .../domain/table/fields/types/ButtonField.ts | 2 +- .../types/ConditionalLookupField.spec.ts | 44 + .../fields/types/ConditionalLookupField.ts | 22 +- .../fields/types/ConditionalRollupField.ts | 33 +- .../table/fields/types/FieldCondition.ts | 31 +- .../table/fields/types/LinkField.spec.ts | 134 +- .../domain/table/fields/types/LinkField.ts | 88 +- .../table/fields/types/LookupField.spec.ts | 221 ++ .../domain/table/fields/types/LookupField.ts | 88 +- .../domain/table/fields/types/RollupField.ts | 19 +- .../FieldCreationSideEffectVisitor.spec.ts | 24 +- .../FieldCreationSideEffectVisitor.ts | 5 +- .../fields/visitors/FieldOptionsDtoVisitor.ts | 2 +- .../records/specs/RecordConditionOperators.ts | 4 + .../specs/RecordConditionSpecBuilder.spec.ts | 4 + .../src/domain/table/resolveFormulaFields.ts | 35 +- .../specs/TableUpdateFieldDbFieldNameSpec.ts | 5 +- .../specs/TableUpdateViewColumnMetaSpec.ts | 130 +- .../TableUpdateViewColumnMetaSpec.spec.ts | 62 + .../TableEventGeneratingSpecVisitor.ts | 28 +- .../specs/visitors/TableSpecEventVisitor.ts | 29 +- .../TableEventGeneratingSpecVisitor.spec.ts | 6 +- .../v2/core/src/ports/mappers/TableMapper.ts | 2 + .../defaults/DefaultTableMapper.spec.ts | 69 + .../mappers/defaults/DefaultTableMapper.ts | 155 +- .../src/ports/memory/AsyncMemoryEventBus.ts | 71 +- .../src/schemas/field/tableField.schema.ts | 37 +- packages/v2/e2e/src/create-field/README.md | 35 + .../src/create-field/button/button.spec.ts | 59 + .../conditionalLookup/cross-base.spec.ts | 126 + .../conditionalRollup.spec.ts | 133 + .../conditionalRollup/cross-base.spec.ts | 150 ++ .../src/create-field/formula/formula.spec.ts | 69 + .../create-field/lookup/cross-base.spec.ts | 145 ++ .../src/create-field/lookup/lookup.spec.ts | 97 + .../create-field/rollup/cross-base.spec.ts | 155 ++ .../src/create-field/rollup/rollup.spec.ts | 112 + .../singleLineText/singleLineText.spec.ts | 138 + packages/v2/e2e/src/createField.e2e.spec.ts | 342 ++- .../v2/e2e/src/duplicateField.e2e.spec.ts | 281 +- packages/v2/e2e/src/formula.e2e.spec.ts | 194 +- .../attachment/conversion/to-lookup.spec.ts | 2 +- .../checkbox/conversion/to-lookup.spec.ts | 2 +- .../computed/record-value-seeding.spec.ts | 35 +- .../date/conversion/to-lookup.spec.ts | 2 +- .../longText/conversion/to-lookup.spec.ts | 2 +- .../conversion/to-lookup.spec.ts | 2 +- .../number/conversion/to-lookup.spec.ts | 2 +- .../rating/conversion/to-lookup.spec.ts | 2 +- .../conversion/to-lookup.spec.ts | 4 +- .../singleSelect/conversion/to-lookup.spec.ts | 2 +- .../user/conversion/to-lookup.spec.ts | 2 +- .../src/DatetimeDiffParity.spec.ts | 75 + .../src/FormulaSqlPgExpressionBuilder.ts | 182 +- .../src/FormulaSqlPgFunctions.ts | 86 +- .../formula-sql-pg/src/FromNowToNow.spec.ts | 2 +- .../v2/formula-sql-pg/src/PgSqlHelpers.ts | 8 +- .../__snapshots__/ArrayFunctions.spec.ts.snap | 80 +- .../BinaryOperators.spec.ts.snap | 384 +-- .../__snapshots__/DateFunctions.spec.ts.snap | 2114 ++++++++++----- .../IfBranchNormalization.spec.ts.snap | 8 +- .../LogicalFunctions.spec.ts.snap | 380 +-- .../NumericFunctions.spec.ts.snap | 2256 ++++++++--------- .../__snapshots__/TextFunctions.spec.ts.snap | 404 +-- .../commands/CreateFieldHandler.db.spec.ts | 287 ++- .../commands/DuplicateFieldHandler.db.spec.ts | 92 + pnpm-lock.yaml | 220 +- 161 files changed, 11339 insertions(+), 3175 deletions(-) create mode 100644 apps/nestjs-backend/src/features/export/metrics/export-tracing.service.ts create mode 100644 apps/nestjs-backend/src/features/field/model/factory.spec.ts create mode 100644 apps/nestjs-backend/src/features/import/metrics/import-tracing.service.ts create mode 100644 apps/nestjs-backend/src/tracing/base-tracing.service.ts create mode 100644 packages/core/src/errors/extract-error-message.ts create mode 100644 packages/openapi/src/admin/setting/ai-key-stats.ts create mode 100644 packages/v2/contract-http-implementation/src/handlers/tables/duplicateField.ts create mode 100644 packages/v2/contract-http/src/table/duplicateField.ts create mode 100644 packages/v2/core/src/domain/table/specs/__tests__/TableUpdateViewColumnMetaSpec.spec.ts create mode 100644 packages/v2/e2e/src/create-field/README.md create mode 100644 packages/v2/e2e/src/create-field/button/button.spec.ts create mode 100644 packages/v2/e2e/src/create-field/conditionalLookup/cross-base.spec.ts create mode 100644 packages/v2/e2e/src/create-field/conditionalRollup/conditionalRollup.spec.ts create mode 100644 packages/v2/e2e/src/create-field/conditionalRollup/cross-base.spec.ts create mode 100644 packages/v2/e2e/src/create-field/formula/formula.spec.ts create mode 100644 packages/v2/e2e/src/create-field/lookup/cross-base.spec.ts create mode 100644 packages/v2/e2e/src/create-field/lookup/lookup.spec.ts create mode 100644 packages/v2/e2e/src/create-field/rollup/cross-base.spec.ts create mode 100644 packages/v2/e2e/src/create-field/rollup/rollup.spec.ts create mode 100644 packages/v2/e2e/src/create-field/singleLineText/singleLineText.spec.ts create mode 100644 packages/v2/formula-sql-pg/src/DatetimeDiffParity.spec.ts create mode 100644 packages/v2/test-node/src/commands/DuplicateFieldHandler.db.spec.ts diff --git a/apps/nestjs-backend/package.json b/apps/nestjs-backend/package.json index e00c1a5fe..817625422 100644 --- a/apps/nestjs-backend/package.json +++ b/apps/nestjs-backend/package.json @@ -122,17 +122,17 @@ "webpack": "5.91.0" }, "dependencies": { - "@ai-sdk/amazon-bedrock": "4.0.41", - "@ai-sdk/anthropic": "3.0.31", - "@ai-sdk/azure": "3.0.24", - "@ai-sdk/cohere": "3.0.16", - "@ai-sdk/deepseek": "2.0.15", - "@ai-sdk/google": "3.0.18", - "@ai-sdk/mistral": "3.0.16", - "@ai-sdk/openai": "3.0.23", - "@ai-sdk/openai-compatible": "2.0.24", - "@ai-sdk/togetherai": "2.0.27", - "@ai-sdk/xai": "3.0.43", + "@ai-sdk/amazon-bedrock": "4.0.69", + "@ai-sdk/anthropic": "3.0.50", + "@ai-sdk/azure": "3.0.38", + "@ai-sdk/cohere": "3.0.22", + "@ai-sdk/deepseek": "2.0.21", + "@ai-sdk/google": "3.0.34", + "@ai-sdk/mistral": "3.0.21", + "@ai-sdk/openai": "3.0.37", + "@ai-sdk/openai-compatible": "2.0.31", + "@ai-sdk/togetherai": "2.0.35", + "@ai-sdk/xai": "3.0.60", "@an-epiphany/websocket-json-stream": "1.2.0", "@aws-sdk/client-s3": "3.609.0", "@aws-sdk/lib-storage": "3.609.0", @@ -153,7 +153,7 @@ "@nestjs/swagger": "7.3.0", "@nestjs/terminus": "10.2.3", "@nestjs/websockets": "10.3.5", - "@openrouter/ai-sdk-provider": "2.1.1", + "@openrouter/ai-sdk-provider": "2.2.3", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.5.0", "@opentelemetry/exporter-logs-otlp-http": "0.201.1", @@ -191,7 +191,7 @@ "@teable/v2-di": "workspace:*", "@teable/v2-import": "workspace:*", "@valibot/to-json-schema": "1.3.0", - "ai": "6.0.62", + "ai": "6.0.105", "ajv": "8.12.0", "archiver": "7.0.1", "axios": "1.7.7", diff --git a/apps/nestjs-backend/src/features/base/base-import-processor/base-import-attachments.processor.ts b/apps/nestjs-backend/src/features/base/base-import-processor/base-import-attachments.processor.ts index e934a89c7..3a5a0d9d2 100644 --- a/apps/nestjs-backend/src/features/base/base-import-processor/base-import-attachments.processor.ts +++ b/apps/nestjs-backend/src/features/base/base-import-processor/base-import-attachments.processor.ts @@ -24,7 +24,6 @@ export const BASE_IMPORT_ATTACHMENTS_QUEUE = 'base-import-attachments-queue'; @Processor(BASE_IMPORT_ATTACHMENTS_QUEUE) export class BaseImportAttachmentsQueueProcessor extends WorkerHost { private logger = new Logger(BaseImportAttachmentsQueueProcessor.name); - private processedJobs = new Set(); constructor( private readonly prismaService: PrismaService, @@ -36,19 +35,11 @@ export class BaseImportAttachmentsQueueProcessor extends WorkerHost { } public async process(job: Job) { - const jobId = String(job.id); - if (this.processedJobs.has(jobId)) { - this.logger.log(`Job ${jobId} already processed, skipping`); - return; - } - - this.processedJobs.add(jobId); - try { await this.handleBaseImportAttachments(job); } catch (error) { this.logger.error( - `Process base import attachments failed: ${(error as Error)?.message}`, + `[base import attachment] Process base import attachments failed: ${(error as Error)?.message}`, (error as Error)?.stack ); } @@ -109,126 +100,75 @@ export class BaseImportAttachmentsQueueProcessor extends WorkerHost { StorageAdapter.getBucket(UploadType.Import), path ); - const parser = unzipper.Parse(); + const parser = unzipper.Parse({ forceStream: true }); zipStream.pipe(parser); const bucket = StorageAdapter.getBucket(UploadType.Table); - return new Promise((resolve, reject) => { - let processingFiles = 0; - let hasError = false; + try { + for await (const entry of parser.pipe(new PassThrough({ objectMode: true }))) { + await this.processAttachmentEntry(entry, bucket); + } - parser.on('entry', (entry) => { - const filePath = entry.path; - const fileSuffix = filePath.split('.').pop(); - if ( - filePath.startsWith('attachments/') && - entry.type !== 'Directory' && - fileSuffix !== 'csv' - ) { - processingFiles++; + this.logger.log(`[base import attachment] all finished`); + } finally { + zipStream.destroy(); + } + } - const passThrough = new PassThrough(); - entry.pipe(passThrough); + private async processAttachmentEntry(entry: unzipper.Entry, bucket: string) { + const filePath = entry.path; + const fileSuffix = filePath.split('.').pop() ?? ''; - const token = filePath.replace('attachments/', '').split('.')[0]; - const isThumbnail = token.includes('thumbnail__'); - const fileSuffix = filePath.replace('attachments/', '').split('.').pop(); - const pathDir = StorageAdapter.getDir(UploadType.Table); - const mimeTypeFromExtension = this.getFileMimeType(fileSuffix); + if ( + !filePath.startsWith('attachments/') || + entry.type === 'Directory' || + fileSuffix === 'csv' + ) { + entry.autodrain(); + return; + } - const finalPath = isThumbnail - ? `table/${token.split('__')[1].split('.')[0]}` - : `${pathDir}/${token}`; + let passThrough: PassThrough | undefined; + try { + const token = filePath.replace('attachments/', '').split('.')[0]; + const isThumbnail = token.includes('thumbnail__'); + const mimeType = this.getFileMimeType(fileSuffix); + const pathDir = StorageAdapter.getDir(UploadType.Table); + const finalPath = isThumbnail + ? `table/${token.split('__')[1].split('.')[0]}` + : `${pathDir}/${token}`; + const finalToken = isThumbnail ? token.split('__')[1].split('.')[0] : token; - const finalToken = isThumbnail ? token.split('__')[1].split('.')[0] : token; + this.logger.log(`[base import attachment] start upload: ${token}`); - this.logger.log(`start upload attachment: ${token}`); - - // this.storageAdapter - // .uploadFile(bucket, finalPath, passThrough, { - // // eslint-disable-next-line @typescript-eslint/naming-convention - // 'Content-Type': mimeTypeFromExtension, - // }) - // .then(() => { - // this.logger.log(`attachment finished: ${token}`); - // processingFiles--; - // checkComplete(); - // }) - // .catch((err) => { - // this.logger.error(`attachment upload error ${token}: ${err.message}`); - // hasError = true; - // processingFiles--; - // checkComplete(); - // }); - - // if the token file is existed, skip the upload - this.prismaService - .txClient() - .attachments.findUnique({ - where: { - token: finalToken, - }, - select: { - id: true, - }, - }) - .then(async (res) => { - if (res) { - this.logger.log(`attachment already exists: ${token}`); - processingFiles--; - checkComplete(); - return; - } - // update attachment - await this.storageAdapter.uploadFileStream(bucket, finalPath, passThrough, { - // eslint-disable-next-line @typescript-eslint/naming-convention - 'Content-Type': mimeTypeFromExtension, - }); - - this.logger.log(`attachment finished: ${token}`); - processingFiles--; - checkComplete(); - }) - .catch((err) => { - this.logger.error(`attachment upload error ${token}: ${err.message}`); - hasError = true; - processingFiles--; - checkComplete(); - }); - } else { - entry.autodrain(); - } + const existing = await this.prismaService.txClient().attachments.findUnique({ + where: { token: finalToken }, + select: { id: true }, }); - const checkComplete = () => { - if (processingFiles === 0) { - if (hasError) { - reject(new Error('upload attachments error')); - } else { - parser.end(); - parser.destroy(); - zipStream.destroy(); - } + if (existing) { + this.logger.log(`[base import attachment] already exists: ${token}`); + entry.autodrain(); + return; + } - if (parser.closed) { - resolve(true); - } - } - }; + passThrough = new PassThrough(); + entry.pipe(passThrough); - parser.on('close', () => { - this.logger.log(`import attachments success`); - if (processingFiles === 0) { - resolve(true); - } + await this.storageAdapter.uploadFileStream(bucket, finalPath, passThrough, { + // eslint-disable-next-line @typescript-eslint/naming-convention + 'Content-Type': mimeType, }); - parser.on('error', (err) => { - this.logger.error(`import attachments error: ${err.message}`); - hasError = true; - reject(err); - }); - }); + this.logger.log(`[base import attachment] ${token} finished: ${token}`); + } catch (err) { + this.logger.error(`[base import attachment] upload error: ${(err as Error).message}`); + if (passThrough) { + passThrough.resume(); + } else { + entry.autodrain(); + } + } } @OnWorkerEvent('completed') diff --git a/apps/nestjs-backend/src/features/export/metrics/export-metrics.module.ts b/apps/nestjs-backend/src/features/export/metrics/export-metrics.module.ts index 0d566d49d..a096c1ca2 100644 --- a/apps/nestjs-backend/src/features/export/metrics/export-metrics.module.ts +++ b/apps/nestjs-backend/src/features/export/metrics/export-metrics.module.ts @@ -1,8 +1,9 @@ import { Module } from '@nestjs/common'; import { ExportMetricsService } from './export-metrics.service'; +import { ExportTracingService } from './export-tracing.service'; @Module({ - providers: [ExportMetricsService], - exports: [ExportMetricsService], + providers: [ExportMetricsService, ExportTracingService], + exports: [ExportMetricsService, ExportTracingService], }) export class ExportMetricsModule {} diff --git a/apps/nestjs-backend/src/features/export/metrics/export-metrics.service.ts b/apps/nestjs-backend/src/features/export/metrics/export-metrics.service.ts index 09781d2eb..5e8671129 100644 --- a/apps/nestjs-backend/src/features/export/metrics/export-metrics.service.ts +++ b/apps/nestjs-backend/src/features/export/metrics/export-metrics.service.ts @@ -17,13 +17,6 @@ export class ExportMetricsService { ], }, }); - private readonly exportRows = this.meter.createHistogram('data.export.rows', { - description: 'Number of rows per export task', - unit: 'rows', - advice: { - explicitBucketBoundaries: [10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000], - }, - }); private readonly exportErrors = this.meter.createCounter('data.export.errors', { description: 'Total number of export errors', }); @@ -32,8 +25,7 @@ export class ExportMetricsService { this.exportTotal.add(1, { format }); } - recordExportComplete(attrs: { format: string; rows: number; durationMs: number }): void { - this.exportRows.record(attrs.rows, { format: attrs.format }); + recordExportComplete(attrs: { format: string; durationMs: number }): void { this.exportDuration.record(attrs.durationMs, { format: attrs.format }); } diff --git a/apps/nestjs-backend/src/features/export/metrics/export-tracing.service.ts b/apps/nestjs-backend/src/features/export/metrics/export-tracing.service.ts new file mode 100644 index 000000000..c098962f7 --- /dev/null +++ b/apps/nestjs-backend/src/features/export/metrics/export-tracing.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { BaseTracingService } from '../../../tracing/base-tracing.service'; + +@Injectable() +export class ExportTracingService extends BaseTracingService { + setExportAttributes(attrs: { rows: number }): void { + this.withActiveSpan((span) => { + span.setAttribute('data.export.rows', attrs.rows); + }); + } +} diff --git a/apps/nestjs-backend/src/features/export/open-api/export-open-api.service.ts b/apps/nestjs-backend/src/features/export/open-api/export-open-api.service.ts index 2ee099820..bc30a99df 100644 --- a/apps/nestjs-backend/src/features/export/open-api/export-open-api.service.ts +++ b/apps/nestjs-backend/src/features/export/open-api/export-open-api.service.ts @@ -12,6 +12,7 @@ import { FieldService } from '../../field/field.service'; import { createFieldInstanceByVo } from '../../field/model/factory'; import { RecordService } from '../../record/record.service'; import { ExportMetricsService } from '../metrics/export-metrics.service'; +import { ExportTracingService } from '../metrics/export-tracing.service'; @Injectable() export class ExportOpenApiService { @@ -20,7 +21,8 @@ export class ExportOpenApiService { private readonly fieldService: FieldService, private readonly recordService: RecordService, private readonly prismaService: PrismaService, - @Optional() private readonly exportMetrics?: ExportMetricsService + @Optional() private readonly exportMetrics?: ExportMetricsService, + @Optional() private readonly exportTracing?: ExportTracingService ) {} async exportCsvFromTable(response: Response, tableId: string, query?: IExportCsvRo) { const exportStartTime = Date.now(); @@ -156,9 +158,9 @@ export class ExportOpenApiService { isOver = true; // end the stream csvStream.push(null); + this.exportTracing?.setExportAttributes({ rows: count }); this.exportMetrics?.recordExportComplete({ format: 'csv', - rows: count, durationMs: Date.now() - exportStartTime, }); break; diff --git a/apps/nestjs-backend/src/features/field/model/factory.spec.ts b/apps/nestjs-backend/src/features/field/model/factory.spec.ts new file mode 100644 index 000000000..b4aceae62 --- /dev/null +++ b/apps/nestjs-backend/src/features/field/model/factory.spec.ts @@ -0,0 +1,54 @@ +import type { IFieldVo } from '@teable/core'; +import { FieldType } from '@teable/core'; +import { describe, expect, it } from 'vitest'; + +import { createFieldInstanceByVo } from './factory'; + +const baseField = { + id: 'fldFactorySpec00001', + name: 'Factory Field', + dbFieldName: 'factory_field', + unique: false, + options: {}, +} as const; + +describe('createFieldInstanceByVo', () => { + it('normalizes v2 conditionalLookup using innerType and innerOptions', () => { + const field = { + ...baseField, + type: 'conditionalLookup', + isLookup: true, + isConditionalLookup: true, + options: { + innerType: FieldType.Number, + innerOptions: { + formatting: { type: 'decimal', precision: 1 }, + }, + }, + } as unknown as IFieldVo; + + const instance = createFieldInstanceByVo(field); + + expect(instance.type).toBe(FieldType.Number); + expect(instance.isLookup).toBe(true); + expect(instance.isConditionalLookup).toBe(true); + expect(instance.options).toEqual({ + formatting: { type: 'decimal', precision: 1 }, + }); + }); + + it('falls back to singleLineText when conditionalLookup innerType is missing', () => { + const field = { + ...baseField, + type: 'conditionalLookup', + options: {}, + } as unknown as IFieldVo; + + const instance = createFieldInstanceByVo(field); + + expect(instance.type).toBe(FieldType.SingleLineText); + expect(instance.isLookup).toBe(true); + expect(instance.isConditionalLookup).toBe(true); + expect(instance.options).toEqual({}); + }); +}); diff --git a/apps/nestjs-backend/src/features/field/model/factory.ts b/apps/nestjs-backend/src/features/field/model/factory.ts index 1f077c0d2..07ae2d710 100644 --- a/apps/nestjs-backend/src/features/field/model/factory.ts +++ b/apps/nestjs-backend/src/features/field/model/factory.ts @@ -103,50 +103,78 @@ export function createFieldInstanceByRaw(fieldRaw: Field) { return createFieldInstanceByVo(rawField2FieldObj(fieldRaw)); } +const normalizeConditionalLookupFieldVo = (field: IFieldVo): IFieldVo => { + if (field.type !== ('conditionalLookup' as FieldType)) { + return field; + } + + const options = + field.options && typeof field.options === 'object' && !Array.isArray(field.options) + ? (field.options as Record) + : {}; + const innerTypeRaw = options.innerType; + const innerOptionsRaw = options.innerOptions; + const innerType = + typeof innerTypeRaw === 'string' ? (innerTypeRaw as FieldType) : FieldType.SingleLineText; + const innerOptions = + innerOptionsRaw && typeof innerOptionsRaw === 'object' && !Array.isArray(innerOptionsRaw) + ? (innerOptionsRaw as Record) + : {}; + + return { + ...field, + type: innerType, + options: innerOptions, + isLookup: true, + isConditionalLookup: true, + }; +}; + export function createFieldInstanceByVo(field: IFieldVo) { - switch (field.type) { + const normalizedField = normalizeConditionalLookupFieldVo(field); + switch (normalizedField.type) { case FieldType.SingleLineText: - return plainToInstance(SingleLineTextFieldDto, field); + return plainToInstance(SingleLineTextFieldDto, normalizedField); case FieldType.LongText: - return plainToInstance(LongTextFieldDto, field); + return plainToInstance(LongTextFieldDto, normalizedField); case FieldType.Number: - return plainToInstance(NumberFieldDto, field); + return plainToInstance(NumberFieldDto, normalizedField); case FieldType.SingleSelect: - return plainToInstance(SingleSelectFieldDto, field); + return plainToInstance(SingleSelectFieldDto, normalizedField); case FieldType.MultipleSelect: - return plainToInstance(MultipleSelectFieldDto, field); + return plainToInstance(MultipleSelectFieldDto, normalizedField); case FieldType.Link: - return plainToInstance(LinkFieldDto, field); + return plainToInstance(LinkFieldDto, normalizedField); case FieldType.Formula: - return plainToInstance(FormulaFieldDto, field); + return plainToInstance(FormulaFieldDto, normalizedField); case FieldType.Attachment: - return plainToInstance(AttachmentFieldDto, field); + return plainToInstance(AttachmentFieldDto, normalizedField); case FieldType.Date: - return plainToInstance(DateFieldDto, field); + return plainToInstance(DateFieldDto, normalizedField); case FieldType.Checkbox: - return plainToInstance(CheckboxFieldDto, field); + return plainToInstance(CheckboxFieldDto, normalizedField); case FieldType.Rollup: - return plainToInstance(RollupFieldDto, field); + return plainToInstance(RollupFieldDto, normalizedField); case FieldType.ConditionalRollup: - return plainToInstance(ConditionalRollupFieldDto, field); + return plainToInstance(ConditionalRollupFieldDto, normalizedField); case FieldType.Rating: - return plainToInstance(RatingFieldDto, field); + return plainToInstance(RatingFieldDto, normalizedField); case FieldType.AutoNumber: - return plainToInstance(AutoNumberFieldDto, field); + return plainToInstance(AutoNumberFieldDto, normalizedField); case FieldType.CreatedTime: - return plainToInstance(CreatedTimeFieldDto, field); + return plainToInstance(CreatedTimeFieldDto, normalizedField); case FieldType.LastModifiedTime: - return plainToInstance(LastModifiedTimeFieldDto, field); + return plainToInstance(LastModifiedTimeFieldDto, normalizedField); case FieldType.User: - return plainToInstance(UserFieldDto, field); + return plainToInstance(UserFieldDto, normalizedField); case FieldType.CreatedBy: - return plainToInstance(CreatedByFieldDto, field); + return plainToInstance(CreatedByFieldDto, normalizedField); case FieldType.LastModifiedBy: - return plainToInstance(LastModifiedByFieldDto, field); + return plainToInstance(LastModifiedByFieldDto, normalizedField); case FieldType.Button: - return plainToInstance(ButtonFieldDto, field); + return plainToInstance(ButtonFieldDto, normalizedField); default: - assertNever(field.type); + assertNever(normalizedField.type); } } diff --git a/apps/nestjs-backend/src/features/field/open-api/field-open-api-v2.service.spec.ts b/apps/nestjs-backend/src/features/field/open-api/field-open-api-v2.service.spec.ts index 48dfa5f2e..41b3e4f85 100644 --- a/apps/nestjs-backend/src/features/field/open-api/field-open-api-v2.service.spec.ts +++ b/apps/nestjs-backend/src/features/field/open-api/field-open-api-v2.service.spec.ts @@ -1,11 +1,29 @@ /* eslint-disable sonarjs/no-identical-functions */ /* eslint-disable sonarjs/no-duplicate-string */ /* eslint-disable @typescript-eslint/naming-convention */ -import { CellValueType, DbFieldType, type IFieldVo } from '@teable/core'; +import { CellValueType, DbFieldType, getDefaultFormatting, type IFieldVo } from '@teable/core'; import { describe, expect, it } from 'vitest'; import { FieldOpenApiV2Service } from './field-open-api-v2.service'; type ITestFieldOpenApiV2Service = { + mapLegacyCreateFieldToV2: ( + ro: Record, + table?: { + getField: ( + predicate: (candidate: { + id: () => { equals: (id: unknown) => boolean }; + relationship: () => { toString: () => string }; + }) => boolean + ) => + | { + isErr: () => false; + value: { relationship: () => { toString: () => string } }; + } + | { + isErr: () => true; + }; + } + ) => Record; mapConvertFieldToV2: ( ro: Record, currentField?: Record @@ -15,6 +33,31 @@ type ITestFieldOpenApiV2Service = { currentField?: Record ) => Record; normalizeFieldVo: (field: unknown) => IFieldVo; + hasDuplicatedDbFieldName: ( + table: { getFields: () => Array }, + dbFieldName: string + ) => boolean; + completeLegacyLinkDbConfigForCreate: ( + v2Field: Record, + currentTable: { + dbTableName: () => { + isErr: () => boolean; + value: { value: () => { isErr: () => boolean; value: string } }; + }; + }, + tableQueryService: { + getById: () => Promise<{ + isErr: () => boolean; + value: { + dbTableName: () => { + isErr: () => boolean; + value: { value: () => { isErr: () => boolean; value: string } }; + }; + }; + }>; + }, + context: Record + ) => Promise>; }; const createService = () => @@ -202,6 +245,40 @@ describe('FieldOpenApiV2Service mapConvertFieldToV2', () => { }); }); + it('omits incomplete conditionalRollup result type in convert payload', () => { + const service = createService(); + const mapped = service.mapConvertFieldToV2({ + type: 'conditionalRollup', + options: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + expression: 'sum({values})', + filter: { + conjunction: 'and', + filterSet: [{ fieldId: 'fldStatus000000001', operator: 'is', value: 'Active' }], + }, + }, + cellValueType: 'number', + }); + + expect(mapped).toEqual({ + type: 'conditionalRollup', + options: { + expression: 'sum({values})', + }, + config: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: 'fldStatus000000001', operator: 'is', value: 'Active' }], + }, + }, + }, + }); + }); + it('maps conditional lookup convert with carried result type from current field', () => { const service = createService(); const mapped = service.mapConvertFieldToV2( @@ -451,6 +528,391 @@ describe('FieldOpenApiV2Service mapConvertFieldToV2', () => { }); }); +describe('FieldOpenApiV2Service mapLegacyCreateFieldToV2', () => { + it('passes dbFieldName through create payload', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'singleLineText', + name: 'TextField', + dbFieldName: 'fldCustomCreateField001', + }); + + expect(mapped).toMatchObject({ + type: 'singleLineText', + name: 'TextField', + dbFieldName: 'fldCustomCreateField001', + }); + }); + + it('passes aiConfig through create payload', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'singleLineText', + aiConfig: { + type: 'summary', + sourceFieldId: 'fldSource000000001', + }, + }); + + expect(mapped).toMatchObject({ + type: 'singleLineText', + aiConfig: { + type: 'summary', + sourceFieldId: 'fldSource000000001', + }, + }); + }); + + it('does not keep legacy false lookup multiplicity without link relationship context', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'singleLineText', + isLookup: true, + isMultipleCellValue: false, + lookupOptions: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + linkFieldId: 'fldLink000000000001', + }, + }); + + expect(mapped).toMatchObject({ + type: 'lookup', + options: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + linkFieldId: 'fldLink000000000001', + }, + }); + expect(mapped).not.toHaveProperty('isMultipleCellValue'); + }); + + it('does not derive lookup multiplicity at openapi mapping layer', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'multipleSelect', + isLookup: true, + lookupOptions: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + linkFieldId: 'fldLink000000000001', + }, + }); + + expect(mapped).toMatchObject({ + type: 'lookup', + options: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + linkFieldId: 'fldLink000000000001', + }, + }); + expect(mapped).not.toHaveProperty('isMultipleCellValue'); + }); + + it('marks legacy lookup create payload to derive multiplicity in domain layer', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'singleLineText', + isLookup: true, + lookupOptions: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + linkFieldId: 'fldLink000000000001', + }, + }); + + expect(mapped).toMatchObject({ + type: 'lookup', + legacyMultiplicityDerivation: true, + }); + }); + + it('keeps explicit true lookup multiplicity from legacy payload', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'date', + isLookup: true, + isMultipleCellValue: true, + lookupOptions: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + linkFieldId: 'fldLink000000000001', + }, + }); + + expect(mapped).toMatchObject({ + type: 'lookup', + isMultipleCellValue: true, + options: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + linkFieldId: 'fldLink000000000001', + }, + }); + }); + + it('maps conditional lookup create payload to v2 conditionalLookup input', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'number', + isLookup: true, + isConditionalLookup: true, + options: { + formatting: { + type: 'currency', + precision: 1, + symbol: '¥', + }, + }, + lookupOptions: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + filter: { + conjunction: 'and', + filterSet: [{ fieldId: 'fldStatus000000001', operator: 'is', value: 'Active' }], + }, + }, + }); + + expect(mapped).toMatchObject({ + type: 'conditionalLookup', + options: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: 'fldStatus000000001', operator: 'is', value: 'Active' }], + }, + }, + }, + }); + expect(mapped.id).toEqual(expect.stringMatching(/^fld[\da-zA-Z]{16}$/)); + }); + + it('omits incomplete conditionalRollup result type in create payload', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'conditionalRollup', + cellValueType: 'number', + options: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + expression: 'sum({values})', + filter: { + conjunction: 'and', + filterSet: [{ fieldId: 'fldStatus000000001', operator: 'is', value: 'Active' }], + }, + }, + }); + + expect(mapped).toEqual({ + id: expect.any(String), + type: 'conditionalRollup', + options: { + expression: 'sum({values})', + }, + config: { + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: 'fldStatus000000001', operator: 'is', value: 'Active' }], + }, + }, + }, + }); + }); + + it('maps rollup create payload and splits config from options', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + id: 'fldCreate0000000001', + type: 'rollup', + options: { + linkFieldId: 'fldLink000000000001', + lookupFieldId: 'fldLookup000000001', + foreignTableId: 'tblForeign00000001', + expression: 'sum({values})', + }, + }); + + expect(mapped).toEqual({ + id: 'fldCreate0000000001', + type: 'rollup', + options: { + expression: 'sum({values})', + }, + config: { + linkFieldId: 'fldLink000000000001', + lookupFieldId: 'fldLookup000000001', + foreignTableId: 'tblForeign00000001', + }, + }); + }); + + it('keeps link db config fields in create payload', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'link', + options: { + relationship: 'manyMany', + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + symmetricFieldId: 'fldSymmetric0000001', + fkHostTableName: 'bseTestBaseId.junction_custom', + selfKeyName: '__fk_fldSymmetric0000001', + foreignKeyName: '__fk_fldCreate0000001', + }, + }); + + expect(mapped).toMatchObject({ + type: 'link', + options: { + relationship: 'manyMany', + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + symmetricFieldId: 'fldSymmetric0000001', + fkHostTableName: 'bseTestBaseId.junction_custom', + selfKeyName: '__fk_fldSymmetric0000001', + foreignKeyName: '__fk_fldCreate0000001', + }, + }); + }); + + it('normalizes UTC to utc in create payload options', () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + type: 'formula', + options: { + expression: 'NOW()', + timeZone: 'UTC', + formatting: { + date: 'YYYY-MM-DD', + time: 'HH:mm', + timeZone: 'UTC', + }, + }, + }); + + expect(mapped).toMatchObject({ + type: 'formula', + options: { + expression: 'NOW()', + timeZone: 'utc', + formatting: { + date: 'YYYY-MM-DD', + time: 'HH:mm', + timeZone: 'utc', + }, + }, + }); + }); + + it('fills link db config for manyOne when legacy payload misses it', async () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + id: 'fldCreate0000000001', + type: 'link', + options: { + relationship: 'manyOne', + foreignTableId: 'tblForeign00000001', + lookupFieldId: 'fldLookup000000001', + }, + }); + + const currentTable = { + dbTableName: () => ({ + isErr: () => false, + value: { + value: () => ({ isErr: () => false, value: 'bseTestBaseId.tblCurrentTable0001' }), + }, + }), + }; + + const completed = await service.completeLegacyLinkDbConfigForCreate( + mapped, + currentTable, + { + getById: async () => ({ + isErr: () => true, + value: currentTable, + }), + }, + {} + ); + + expect(completed).toMatchObject({ + type: 'link', + options: { + relationship: 'manyOne', + fkHostTableName: 'bseTestBaseId.tblCurrentTable0001', + selfKeyName: '__id', + foreignKeyName: '__fk_fldCreate0000000001', + }, + }); + }); + + it('fills link db config for two-way oneMany from foreign table db name', async () => { + const service = createService(); + const mapped = service.mapLegacyCreateFieldToV2({ + id: 'fldCreate0000000002', + type: 'link', + options: { + relationship: 'oneMany', + isOneWay: false, + foreignTableId: 'tblAbCdEfGhIjKlMn01', + lookupFieldId: 'fldLookup000000002', + }, + }); + + const currentTable = { + dbTableName: () => ({ + isErr: () => false, + value: { + value: () => ({ isErr: () => false, value: 'bseTestBaseId.tblCurrentTable0002' }), + }, + }), + }; + + const completed = await service.completeLegacyLinkDbConfigForCreate( + mapped, + currentTable, + { + getById: async () => ({ + isErr: () => false, + value: { + dbTableName: () => ({ + isErr: () => false, + value: { + value: () => ({ + isErr: () => false, + value: 'bseTestBaseId.tblForeignPhysical0002', + }), + }, + }), + }, + }), + }, + {} + ); + + expect(completed).toMatchObject({ + type: 'link', + options: { + relationship: 'oneMany', + isOneWay: false, + fkHostTableName: 'bseTestBaseId.tblForeignPhysical0002', + }, + }); + expect((completed.options as { selfKeyName: string }).selfKeyName).toMatch(/^__fk_/); + expect((completed.options as { foreignKeyName: string }).foreignKeyName).toBe('__id'); + expect((completed.options as { symmetricFieldId?: string }).symmetricFieldId).toMatch(/^fld/); + }); +}); + describe('FieldOpenApiV2Service normalizeFieldVo', () => { const createNormalizeService = () => new FieldOpenApiV2Service( @@ -567,6 +1029,51 @@ describe('FieldOpenApiV2Service normalizeFieldVo', () => { expect(vo.dbFieldType).toBe(DbFieldType.Real); }); + it('applies legacy number formatting fallback for numeric rollup expressions', () => { + const service = createNormalizeService(); + const vo = service.normalizeFieldVo({ + id: 'fldRollupNormalize0002', + name: 'Rollup Numeric Fallback', + type: 'rollup', + dbFieldName: 'rollup_numeric_fallback', + cellValueType: 'string', + options: { expression: 'sum({values})' }, + config: { + linkFieldId: 'fldLink000000000001', + lookupFieldId: 'fldLookup000000001', + foreignTableId: 'tblForeign00000001', + }, + }); + + expect((vo.options as Record).formatting).toEqual( + getDefaultFormatting(CellValueType.Number) + ); + }); + + it('does not override existing rollup formatting when expression is numeric', () => { + const service = createNormalizeService(); + const vo = service.normalizeFieldVo({ + id: 'fldRollupNormalize0003', + name: 'Rollup Keep Formatting', + type: 'rollup', + dbFieldName: 'rollup_keep_formatting', + options: { + expression: 'sum({values})', + formatting: { type: 'decimal', precision: 5 }, + }, + config: { + linkFieldId: 'fldLink000000000001', + lookupFieldId: 'fldLookup000000001', + foreignTableId: 'tblForeign00000001', + }, + }); + + expect((vo.options as Record).formatting).toEqual({ + type: 'decimal', + precision: 5, + }); + }); + it('derives rating field as number type', () => { const service = createNormalizeService(); const vo = service.normalizeFieldVo({ @@ -634,7 +1141,7 @@ describe('FieldOpenApiV2Service normalizeFieldVo', () => { expect((vo.options as Record).symmetricFieldId).toBe('fldSymmetric000001'); }); - it('ensures unique defaults to false when missing', () => { + it('keeps unique undefined when missing', () => { const service = createNormalizeService(); const vo = service.normalizeFieldVo({ id: 'fldTest0000000010', @@ -643,7 +1150,63 @@ describe('FieldOpenApiV2Service normalizeFieldVo', () => { options: {}, }); - expect(vo.unique).toBe(false); + expect(vo.unique).toBeUndefined(); + }); + + it('omits false isMultipleCellValue for v1 compatibility', () => { + const service = createNormalizeService(); + const vo = service.normalizeFieldVo({ + id: 'fldButtonNormalize0001', + name: 'Button', + type: 'button', + dbFieldName: 'button_field', + isMultipleCellValue: false, + options: { + label: 'Run', + color: 'red', + }, + }); + + expect(vo.isMultipleCellValue).toBeUndefined(); + }); + + it('strips undefined keys from options payload', () => { + const service = createNormalizeService(); + const vo = service.normalizeFieldVo({ + id: 'fldButtonNormalize0002', + name: 'Button', + type: 'button', + dbFieldName: 'button_field_2', + options: { + label: 'Run', + workflow: undefined, + }, + }); + + expect(vo.options).toEqual({ + label: 'Run', + }); + }); + + it('omits false isMultipleCellValue for rollup field output compatibility', () => { + const service = createNormalizeService(); + const vo = service.normalizeFieldVo({ + id: 'fldRollupNormalize0001', + name: 'Rollup', + type: 'rollup', + dbFieldName: 'rollup_field', + cellValueType: 'number', + isMultipleCellValue: false, + options: { expression: 'sum({values})' }, + config: { + linkFieldId: 'fldLink000000000001', + lookupFieldId: 'fldLookup000000001', + foreignTableId: 'tblForeign00000001', + }, + }); + + expect(vo.isMultipleCellValue).toBeUndefined(); + expect(vo.cellValueType).toBe(CellValueType.Number); }); it('normalizes lookup options to empty object when source options are null', () => { @@ -664,3 +1227,39 @@ describe('FieldOpenApiV2Service normalizeFieldVo', () => { expect(vo.options).toEqual({}); }); }); + +describe('FieldOpenApiV2Service hasDuplicatedDbFieldName', () => { + it('returns true when dbFieldName already exists in table', () => { + const service = createService(); + const table = { + getFields: () => [ + { + dbFieldName: () => ({ + andThen: ( + fn: (name: { value: () => { isOk: () => boolean; value: string } }) => unknown + ) => fn({ value: () => ({ isOk: () => true, value: 'fld_existing_db_name' }) }), + }), + }, + ], + }; + + expect(service.hasDuplicatedDbFieldName(table, 'fld_existing_db_name')).toBe(true); + }); + + it('returns false when dbFieldName does not exist in table', () => { + const service = createService(); + const table = { + getFields: () => [ + { + dbFieldName: () => ({ + andThen: ( + fn: (name: { value: () => { isOk: () => boolean; value: string } }) => unknown + ) => fn({ value: () => ({ isOk: () => true, value: 'fld_other_db_name' }) }), + }), + }, + ], + }; + + expect(service.hasDuplicatedDbFieldName(table, 'fld_missing_db_name')).toBe(false); + }); +}); diff --git a/apps/nestjs-backend/src/features/field/open-api/field-open-api-v2.service.ts b/apps/nestjs-backend/src/features/field/open-api/field-open-api-v2.service.ts index 8aa7a3222..e066a74e9 100644 --- a/apps/nestjs-backend/src/features/field/open-api/field-open-api-v2.service.ts +++ b/apps/nestjs-backend/src/features/field/open-api/field-open-api-v2.service.ts @@ -1,15 +1,34 @@ /* eslint-disable sonarjs/cognitive-complexity */ import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; -import type { IConvertFieldRo, IFieldVo, IUpdateFieldRo } from '@teable/core'; -import { CellValueType, DbFieldType, FieldKeyType, FieldType, getDbFieldType } from '@teable/core'; +import type { IConvertFieldRo, IFieldRo, IFieldVo, IUpdateFieldRo } from '@teable/core'; import { + CellValueType, + DbFieldType, + FieldKeyType, + FieldType, + generateFieldId, + getDefaultFormatting, + getDbFieldType, +} from '@teable/core'; +import type { IDuplicateFieldRo } from '@teable/openapi'; +import { + executeCreateFieldEndpoint, + executeDuplicateFieldEndpoint, executeUpdateFieldEndpoint, executeUpdateRecordEndpoint, } from '@teable/v2-contract-http-implementation/handlers'; -import { TableId, v2CoreTokens } from '@teable/v2-core'; +import { + DbTableName, + FieldId, + LinkFieldConfig, + LinkRelationship, + TableId, + v2CoreTokens, +} from '@teable/v2-core'; import type { ICommandBus, IExecutionContext, + Table, TableQueryService, ITableMapper, } from '@teable/v2-core'; @@ -44,6 +63,26 @@ export class FieldOpenApiV2Service { private readonly dataLoaderService: DataLoaderService ) {} + private stripUndefinedDeep(value: unknown): unknown { + if (Array.isArray(value)) { + return value.map((item) => this.stripUndefinedDeep(item)); + } + + if (!value || typeof value !== 'object') { + return value; + } + + const result: Record = {}; + for (const [key, nested] of Object.entries(value as Record)) { + if (nested === undefined) { + continue; + } + result[key] = this.stripUndefinedDeep(nested); + } + + return result; + } + private invalidateFieldLoader(tableIds: ReadonlyArray) { const ids = Array.from( new Set(tableIds.filter((id) => typeof id === 'string' && id.length > 0)) @@ -70,10 +109,6 @@ export class FieldOpenApiV2Service { private normalizeFieldVo(field: unknown): IFieldVo { const vo = instanceToPlain(field, { excludePrefixes: ['_'] }) as IFieldVo; - // Ensure unique is always a boolean (v2 persistence omits false, but v1 API expects it) - if (vo.unique == null) { - vo.unique = false; - } const raw = vo as Record; // Translate v2 conditionalRollup DTO to v1 API format. @@ -164,12 +199,6 @@ export class FieldOpenApiV2Service { const linkOpts = vo.options as Record; if (linkOpts.isOneWay === true) { delete linkOpts.symmetricFieldId; - } else if ( - linkOpts.isOneWay === false && - linkOpts.relationship !== 'oneOne' && - linkOpts.relationship !== 'one_one' - ) { - delete linkOpts.isOneWay; } if (raw.meta && typeof raw.meta === 'object') { @@ -187,6 +216,26 @@ export class FieldOpenApiV2Service { } } + if (vo.isMultipleCellValue === false) { + delete raw.isMultipleCellValue; + } + + if (vo.isComputed === true && raw.isPending == null) { + raw.isPending = true; + } + + if (raw.options && typeof raw.options === 'object') { + raw.options = this.denormalizeLegacyTimeZone(this.stripUndefinedDeep(raw.options)); + } + + if (raw.lookupOptions && typeof raw.lookupOptions === 'object') { + raw.lookupOptions = this.stripUndefinedDeep(raw.lookupOptions); + } + + if (raw.aiConfig && typeof raw.aiConfig === 'object') { + raw.aiConfig = this.stripUndefinedDeep(raw.aiConfig); + } + if (vo.type === FieldType.AutoNumber) { vo.cellValueType = CellValueType.Number; vo.dbFieldType = DbFieldType.Integer; @@ -196,6 +245,20 @@ export class FieldOpenApiV2Service { vo.cellValueType = this.deriveCellValueType(vo); } + if (vo.type === FieldType.Rollup && vo.options && typeof vo.options === 'object') { + const options = vo.options as Record; + if (options.formatting == null) { + const fallbackCellValueType = this.shouldApplyLegacyRollupNumberFormatting(vo) + ? CellValueType.Number + : vo.cellValueType; + const defaultFormatting = + fallbackCellValueType != null ? getDefaultFormatting(fallbackCellValueType) : undefined; + if (defaultFormatting) { + options.formatting = defaultFormatting; + } + } + } + // Derive isMultipleCellValue when not present for field types that are always multi-value. if (vo.isMultipleCellValue == null) { const isMultiple = this.deriveIsMultipleCellValue(vo); @@ -269,6 +332,28 @@ export class FieldOpenApiV2Service { } } + private shouldApplyLegacyRollupNumberFormatting(vo: IFieldVo): boolean { + if (vo.type !== FieldType.Rollup) { + return false; + } + const options = + vo.options && typeof vo.options === 'object' && !Array.isArray(vo.options) + ? (vo.options as Record) + : undefined; + const expression = + typeof options?.expression === 'string' ? options.expression.trim().toLowerCase() : ''; + if (!expression) { + return false; + } + return ( + expression.startsWith('sum(') || + expression.startsWith('average(') || + expression.startsWith('count(') || + expression.startsWith('counta(') || + expression.startsWith('countall(') + ); + } + private async getFieldFromV2( tableId: string, fieldId: string, @@ -328,6 +413,12 @@ export class FieldOpenApiV2Service { if (vo.isLookup && vo.lookupOptions && typeof vo.lookupOptions === 'object') { const lookupOpts = vo.lookupOptions as Record; + if (lookupOpts.isOneWay === false) { + delete lookupOpts.isOneWay; + } + if (lookupOpts.symmetricFieldId != null) { + delete lookupOpts.symmetricFieldId; + } const foreignTableId = lookupOpts.foreignTableId; const lookupFieldId = lookupOpts.lookupFieldId; if (typeof foreignTableId === 'string' && typeof lookupFieldId === 'string') { @@ -353,6 +444,7 @@ export class FieldOpenApiV2Service { ...(sourceOptions ?? {}), ...(currentOptions ?? {}), } as IFieldVo['options']; + vo.options = this.denormalizeLegacyTimeZone(vo.options) as IFieldVo['options']; } if (sourceVo.cellValueType != null && vo.cellValueType == null) { @@ -371,6 +463,11 @@ export class FieldOpenApiV2Service { return vo; } + async getField(tableId: string, fieldId: string): Promise { + const context = await this.v2ContextFactory.createContext(); + return this.getFieldFromV2(tableId, fieldId, context); + } + private mapLegacyUpdateFieldToV2( ro: IUpdateFieldRo, currentField?: Record @@ -412,6 +509,541 @@ export class FieldOpenApiV2Service { return mapped; } + private normalizeLegacyTimeZone(value: unknown): unknown { + if (Array.isArray(value)) { + return value.map((item) => this.normalizeLegacyTimeZone(item)); + } + if (!value || typeof value !== 'object') { + return value; + } + + const normalized: Record = {}; + for (const [key, raw] of Object.entries(value as Record)) { + if (key === 'timeZone' && raw === 'UTC') { + normalized[key] = 'utc'; + continue; + } + normalized[key] = this.normalizeLegacyTimeZone(raw); + } + return normalized; + } + + private denormalizeLegacyTimeZone(value: unknown): unknown { + if (Array.isArray(value)) { + return value.map((item) => this.denormalizeLegacyTimeZone(item)); + } + if (!value || typeof value !== 'object') { + return value; + } + + const normalized: Record = {}; + for (const [key, raw] of Object.entries(value as Record)) { + if (key === 'timeZone' && raw === 'utc') { + normalized[key] = 'UTC'; + continue; + } + normalized[key] = this.denormalizeLegacyTimeZone(raw); + } + return normalized; + } + + private getResultTypePair(raw: Record): Record { + const cellValueType = raw.cellValueType; + const isMultipleCellValue = raw.isMultipleCellValue; + + if (typeof cellValueType === 'string' && typeof isMultipleCellValue === 'boolean') { + return isMultipleCellValue ? { cellValueType, isMultipleCellValue } : { cellValueType }; + } + return {}; + } + + private mapLegacyCreateFieldToV2(ro: IFieldRo): Record { + const field = ro as Record; + const base: Record = { + id: typeof field.id === 'string' ? field.id : generateFieldId(), + }; + if (field.name != null) base.name = field.name; + if (typeof field.dbFieldName === 'string') { + base.dbFieldName = field.dbFieldName; + } + if (Object.prototype.hasOwnProperty.call(field, 'description')) { + base.description = field.description ?? null; + } + if (field.notNull != null) base.notNull = field.notNull; + if (field.unique != null) base.unique = field.unique; + if (Object.prototype.hasOwnProperty.call(field, 'aiConfig')) { + base.aiConfig = field.aiConfig ?? null; + } + + if (field.isConditionalLookup) { + const lookupOpts = + ro.lookupOptions && typeof ro.lookupOptions === 'object' && !Array.isArray(ro.lookupOptions) + ? (ro.lookupOptions as Record) + : undefined; + const innerOptions = + ro.options && typeof ro.options === 'object' && !Array.isArray(ro.options) + ? (ro.options as Record) + : undefined; + return this.normalizeLegacyTimeZone({ + ...base, + type: 'conditionalLookup', + ...(typeof field.isMultipleCellValue === 'boolean' + ? { isMultipleCellValue: field.isMultipleCellValue } + : {}), + options: { + ...(lookupOpts?.foreignTableId != null + ? { foreignTableId: lookupOpts.foreignTableId } + : {}), + ...(lookupOpts?.lookupFieldId != null ? { lookupFieldId: lookupOpts.lookupFieldId } : {}), + condition: { + ...(lookupOpts?.filter ? { filter: lookupOpts.filter } : {}), + ...(lookupOpts?.sort ? { sort: lookupOpts.sort } : {}), + ...(lookupOpts?.limit != null ? { limit: lookupOpts.limit } : {}), + }, + }, + ...(innerOptions && Object.keys(innerOptions).length > 0 ? { innerOptions } : {}), + }) as Record; + } + + if (field.isLookup) { + const lookupOpts = + ro.lookupOptions && typeof ro.lookupOptions === 'object' && !Array.isArray(ro.lookupOptions) + ? (ro.lookupOptions as Record) + : undefined; + const innerOptions = + ro.options && typeof ro.options === 'object' && !Array.isArray(ro.options) + ? (ro.options as Record) + : undefined; + return this.normalizeLegacyTimeZone({ + ...base, + type: 'lookup', + legacyMultiplicityDerivation: true, + ...(field.isMultipleCellValue === true ? { isMultipleCellValue: true } : {}), + options: { + ...(lookupOpts?.linkFieldId != null ? { linkFieldId: lookupOpts.linkFieldId } : {}), + ...(lookupOpts?.lookupFieldId != null ? { lookupFieldId: lookupOpts.lookupFieldId } : {}), + ...(lookupOpts?.foreignTableId != null + ? { foreignTableId: lookupOpts.foreignTableId } + : {}), + ...(lookupOpts?.filter ? { filter: lookupOpts.filter } : {}), + ...(lookupOpts?.sort ? { sort: lookupOpts.sort } : {}), + ...(lookupOpts?.limit != null ? { limit: lookupOpts.limit } : {}), + }, + ...(innerOptions && Object.keys(innerOptions).length > 0 ? { innerOptions } : {}), + }) as Record; + } + + if (ro.type === FieldType.Rollup) { + const opts = (ro.options ?? {}) as Record; + const lookupOpts = + ro.lookupOptions && typeof ro.lookupOptions === 'object' && !Array.isArray(ro.lookupOptions) + ? (ro.lookupOptions as Record) + : undefined; + const linkFieldId = opts.linkFieldId ?? lookupOpts?.linkFieldId; + const lookupFieldId = opts.lookupFieldId ?? lookupOpts?.lookupFieldId; + const foreignTableId = opts.foreignTableId ?? lookupOpts?.foreignTableId; + const shouldIncludeConfig = + linkFieldId != null && lookupFieldId != null && foreignTableId != null; + return this.normalizeLegacyTimeZone({ + ...base, + type: FieldType.Rollup, + ...this.getResultTypePair(field), + options: { + ...(opts.expression != null ? { expression: opts.expression } : {}), + ...(opts.formatting != null ? { formatting: opts.formatting } : {}), + ...(opts.timeZone != null ? { timeZone: opts.timeZone } : {}), + ...(opts.showAs != null ? { showAs: opts.showAs } : {}), + }, + ...(shouldIncludeConfig + ? { + config: { + linkFieldId, + lookupFieldId, + foreignTableId, + }, + } + : {}), + }) as Record; + } + + if (ro.type === FieldType.Link) { + const opts = + ro.options && typeof ro.options === 'object' && !Array.isArray(ro.options) + ? (ro.options as Record) + : {}; + + return this.normalizeLegacyTimeZone({ + ...base, + type: FieldType.Link, + options: { + ...(opts.baseId != null ? { baseId: opts.baseId } : {}), + ...(opts.relationship != null ? { relationship: opts.relationship } : {}), + ...(opts.foreignTableId != null ? { foreignTableId: opts.foreignTableId } : {}), + ...(opts.lookupFieldId != null ? { lookupFieldId: opts.lookupFieldId } : {}), + ...(opts.fkHostTableName != null ? { fkHostTableName: opts.fkHostTableName } : {}), + ...(opts.selfKeyName != null ? { selfKeyName: opts.selfKeyName } : {}), + ...(opts.foreignKeyName != null ? { foreignKeyName: opts.foreignKeyName } : {}), + ...(opts.isOneWay != null ? { isOneWay: opts.isOneWay } : {}), + ...(opts.symmetricFieldId != null ? { symmetricFieldId: opts.symmetricFieldId } : {}), + ...(Object.prototype.hasOwnProperty.call(opts, 'filterByViewId') + ? { filterByViewId: opts.filterByViewId } + : {}), + ...(Object.prototype.hasOwnProperty.call(opts, 'visibleFieldIds') + ? { visibleFieldIds: opts.visibleFieldIds } + : {}), + ...(opts.filter != null ? { filter: opts.filter } : {}), + }, + }) as Record; + } + + if (ro.type === 'conditionalRollup') { + const opts = (ro.options ?? {}) as Record; + const condition = { + ...(opts.filter ? { filter: opts.filter } : {}), + ...(opts.sort ? { sort: opts.sort } : {}), + ...(opts.limit != null ? { limit: opts.limit } : {}), + }; + const shouldIncludeConfig = + opts.foreignTableId != null && + opts.lookupFieldId != null && + Object.keys(condition).length > 0; + return this.normalizeLegacyTimeZone({ + ...base, + type: 'conditionalRollup', + ...this.getResultTypePair(field), + options: { + ...(opts.expression != null ? { expression: opts.expression } : {}), + ...(opts.formatting != null ? { formatting: opts.formatting } : {}), + ...(opts.timeZone != null ? { timeZone: opts.timeZone } : {}), + ...(opts.showAs != null ? { showAs: opts.showAs } : {}), + }, + ...(shouldIncludeConfig + ? { + config: { + foreignTableId: opts.foreignTableId, + lookupFieldId: opts.lookupFieldId, + condition, + }, + } + : {}), + }) as Record; + } + + return this.normalizeLegacyTimeZone({ + ...base, + type: ro.type, + ...(ro.options != null ? { options: ro.options } : {}), + }) as Record; + } + + private getDbTableNameString(table: Table): string | undefined { + const dbTableNameResult = table.dbTableName(); + if (dbTableNameResult.isErr()) { + return undefined; + } + const valueResult = dbTableNameResult.value.value(); + if (valueResult.isErr()) { + return undefined; + } + return valueResult.value; + } + + private hasDuplicatedDbFieldName(table: Table, dbFieldName: string): boolean { + return table.getFields().some((field) => { + const existingDbFieldNameResult = field.dbFieldName().andThen((name) => name.value()); + return existingDbFieldNameResult.isOk() && existingDbFieldNameResult.value === dbFieldName; + }); + } + + private async completeLegacyLinkDbConfigForCreate( + v2Field: Record, + currentTable: Table, + tableQueryService: TableQueryService, + context: IExecutionContext + ): Promise> { + if (v2Field.type !== FieldType.Link) { + return v2Field; + } + + const options = + v2Field.options && typeof v2Field.options === 'object' && !Array.isArray(v2Field.options) + ? (v2Field.options as Record) + : undefined; + if (!options) { + return v2Field; + } + + const hasAnyDbConfig = + options.fkHostTableName != null || + options.selfKeyName != null || + options.foreignKeyName != null; + if (hasAnyDbConfig) { + return v2Field; + } + + const relationshipRaw = options.relationship; + const foreignTableIdRaw = options.foreignTableId; + if (typeof relationshipRaw !== 'string' || typeof foreignTableIdRaw !== 'string') { + return v2Field; + } + + const relationshipResult = LinkRelationship.create(relationshipRaw); + if (relationshipResult.isErr()) { + return v2Field; + } + + const relationship = relationshipResult.value.toString(); + const isOneWay = options.isOneWay === true; + if (relationship === 'manyMany' || (relationship === 'oneMany' && isOneWay)) { + return v2Field; + } + + const fieldIdRaw = v2Field.id; + if (typeof fieldIdRaw !== 'string') { + return v2Field; + } + + let fkHostTableNameValue: string | undefined; + if (relationship === 'oneMany') { + const foreignTableIdResult = TableId.create(foreignTableIdRaw); + if (foreignTableIdResult.isErr()) { + return v2Field; + } + const foreignTableResult = await tableQueryService.getById( + context, + foreignTableIdResult.value + ); + if (foreignTableResult.isErr()) { + return v2Field; + } + fkHostTableNameValue = this.getDbTableNameString(foreignTableResult.value); + } else { + fkHostTableNameValue = this.getDbTableNameString(currentTable); + } + + if (!fkHostTableNameValue) { + return v2Field; + } + + const fieldIdResult = FieldId.create(fieldIdRaw); + if (fieldIdResult.isErr()) { + return v2Field; + } + + let symmetricFieldIdRaw = + typeof options.symmetricFieldId === 'string' ? options.symmetricFieldId : undefined; + if (relationship === 'oneMany' && !isOneWay && !symmetricFieldIdRaw) { + symmetricFieldIdRaw = generateFieldId(); + } + + let symmetricFieldId: FieldId | undefined; + if (symmetricFieldIdRaw) { + const symmetricFieldIdResult = FieldId.create(symmetricFieldIdRaw); + if (symmetricFieldIdResult.isErr()) { + return v2Field; + } + symmetricFieldId = symmetricFieldIdResult.value; + } + + const dbTableNameResult = DbTableName.rehydrate(fkHostTableNameValue); + if (dbTableNameResult.isErr()) { + return v2Field; + } + + const dbConfigResult = LinkFieldConfig.buildDbConfig({ + fkHostTableName: dbTableNameResult.value, + relationship: relationshipResult.value, + fieldId: fieldIdResult.value, + symmetricFieldId, + isOneWay, + }); + if (dbConfigResult.isErr()) { + return v2Field; + } + + const fkHostTableNameResult = dbConfigResult.value.fkHostTableName.value(); + const selfKeyNameResult = dbConfigResult.value.selfKeyName.value(); + const foreignKeyNameResult = dbConfigResult.value.foreignKeyName.value(); + if ( + fkHostTableNameResult.isErr() || + selfKeyNameResult.isErr() || + foreignKeyNameResult.isErr() + ) { + return v2Field; + } + + return { + ...v2Field, + options: { + ...options, + fkHostTableName: fkHostTableNameResult.value, + selfKeyName: selfKeyNameResult.value, + foreignKeyName: foreignKeyNameResult.value, + ...(symmetricFieldIdRaw != null ? { symmetricFieldId: symmetricFieldIdRaw } : {}), + }, + }; + } + + async createField(tableId: string, fieldRo: IFieldRo): Promise { + const container = await this.v2ContainerService.getContainer(); + const commandBus = container.resolve(v2CoreTokens.commandBus); + const tableQueryService = container.resolve(v2CoreTokens.tableQueryService); + const context = await this.v2ContextFactory.createContext(); + const tableIdResult = TableId.create(tableId); + if (tableIdResult.isErr()) { + throw new HttpException('Invalid table id', HttpStatus.BAD_REQUEST); + } + + const tableResult = await tableQueryService.getById(context, tableIdResult.value); + if (tableResult.isErr()) { + const errMsg = tableResult.error.message ?? 'Table not found'; + const isNotFound = + tableResult.error.code === 'table.not_found' || errMsg.includes('not found'); + throw new HttpException( + errMsg, + isNotFound ? HttpStatus.NOT_FOUND : HttpStatus.INTERNAL_SERVER_ERROR + ); + } + + const rawFieldRo = fieldRo as Record; + const rawDbFieldName = rawFieldRo.dbFieldName; + if ( + typeof rawDbFieldName === 'string' && + this.hasDuplicatedDbFieldName(tableResult.value, rawDbFieldName) + ) { + throw new CustomHttpException( + `Db Field name ${rawDbFieldName} already exists in this table`, + getDefaultCodeByStatus(HttpStatus.BAD_REQUEST) + ); + } + + const hasAiConfig = Object.prototype.hasOwnProperty.call(rawFieldRo, 'aiConfig'); + const nextAiConfig = hasAiConfig ? rawFieldRo.aiConfig ?? null : undefined; + const mappedField = this.mapLegacyCreateFieldToV2(fieldRo); + const linkDbCompletedField = await this.completeLegacyLinkDbConfigForCreate( + mappedField, + tableResult.value, + tableQueryService, + context + ); + const v2Field = linkDbCompletedField; + const legacyOrder = + fieldRo && typeof fieldRo === 'object' && 'order' in fieldRo + ? (fieldRo.order as + | { + viewId?: unknown; + orderIndex?: unknown; + } + | undefined) + : undefined; + const normalizedOrder = + typeof legacyOrder?.viewId === 'string' && typeof legacyOrder?.orderIndex === 'number' + ? { + viewId: legacyOrder.viewId, + orderIndex: legacyOrder.orderIndex, + } + : undefined; + const result = await executeCreateFieldEndpoint( + context, + { + baseId: tableResult.value.baseId().toString(), + tableId, + field: v2Field, + ...(normalizedOrder ? { order: normalizedOrder } : {}), + }, + commandBus + ); + + if (result.status === 200 && result.body.ok) { + const tableIdsToInvalidate = [tableId]; + const mappedOptions = + v2Field.options && typeof v2Field.options === 'object' && !Array.isArray(v2Field.options) + ? (v2Field.options as Record) + : undefined; + const mappedConfig = + v2Field.config && typeof v2Field.config === 'object' && !Array.isArray(v2Field.config) + ? (v2Field.config as Record) + : undefined; + if (typeof mappedOptions?.foreignTableId === 'string') { + tableIdsToInvalidate.push(mappedOptions.foreignTableId); + } + if (typeof mappedConfig?.foreignTableId === 'string') { + tableIdsToInvalidate.push(mappedConfig.foreignTableId); + } + this.invalidateFieldLoader(tableIdsToInvalidate); + + if (typeof v2Field.id === 'string') { + const createdField = await this.getFieldFromV2(tableId, v2Field.id, context); + + if (hasAiConfig) { + createdField.aiConfig = nextAiConfig as IFieldVo['aiConfig']; + } + + return createdField; + } + } + + if (!result.body.ok) { + this.throwV2Error(result.body.error, result.status); + } + + throw new HttpException(internalServerError, HttpStatus.INTERNAL_SERVER_ERROR); + } + + async duplicateField( + tableId: string, + fieldId: string, + duplicateFieldRo: IDuplicateFieldRo, + _windowId?: string + ): Promise { + const container = await this.v2ContainerService.getContainer(); + const commandBus = container.resolve(v2CoreTokens.commandBus); + const tableQueryService = container.resolve(v2CoreTokens.tableQueryService); + const context = await this.v2ContextFactory.createContext(); + + const tableIdResult = TableId.create(tableId); + if (tableIdResult.isErr()) { + throw new HttpException('Invalid table id', HttpStatus.BAD_REQUEST); + } + + const tableResult = await tableQueryService.getById(context, tableIdResult.value); + if (tableResult.isErr()) { + const errMsg = tableResult.error.message ?? 'Table not found'; + const isNotFound = + tableResult.error.code === 'table.not_found' || errMsg.includes('not found'); + throw new HttpException( + errMsg, + isNotFound ? HttpStatus.NOT_FOUND : HttpStatus.INTERNAL_SERVER_ERROR + ); + } + + const duplicateResult = await executeDuplicateFieldEndpoint( + context, + { + baseId: tableResult.value.baseId().toString(), + tableId, + fieldId, + includeRecordValues: true, + newFieldName: duplicateFieldRo.name, + viewId: duplicateFieldRo.viewId, + }, + commandBus + ); + + if (!(duplicateResult.status === 200 && duplicateResult.body.ok)) { + if (!duplicateResult.body.ok) { + this.throwV2Error(duplicateResult.body.error, duplicateResult.status); + } + throw new HttpException(internalServerError, HttpStatus.INTERNAL_SERVER_ERROR); + } + + const duplicatedFieldId = duplicateResult.body.data.newFieldId; + + this.invalidateFieldLoader([tableId]); + + return this.getFieldFromV2(tableId, duplicatedFieldId, context); + } + async updateField(tableId: string, fieldId: string, updateFieldRo: IUpdateFieldRo) { const container = await this.v2ContainerService.getContainer(); const commandBus = container.resolve(v2CoreTokens.commandBus); @@ -630,8 +1262,7 @@ export class FieldOpenApiV2Service { return { ...base, type: 'conditionalRollup', - cellValueType: (ro as Record).cellValueType, - isMultipleCellValue: (ro as Record).isMultipleCellValue, + ...this.getResultTypePair(ro as Record), options: { ...(opts.expression != null ? { expression: opts.expression } : {}), ...(opts.formatting != null ? { formatting: opts.formatting } : {}), diff --git a/apps/nestjs-backend/src/features/field/open-api/field-open-api.controller.ts b/apps/nestjs-backend/src/features/field/open-api/field-open-api.controller.ts index 65ed6c0e3..cacb85225 100644 --- a/apps/nestjs-backend/src/features/field/open-api/field-open-api.controller.ts +++ b/apps/nestjs-backend/src/features/field/open-api/field-open-api.controller.ts @@ -90,6 +90,21 @@ export class FieldOpenApiController { @Param('tableId') tableId: string, @Param('fieldId') fieldId: string ): Promise { + const forceV2All = process.env.FORCE_V2_ALL?.toLowerCase() === 'true'; + if (this.cls.get('useV2') || forceV2All) { + const field = await this.fieldOpenApiV2Service.getField(tableId, fieldId); + if (field.hasError == null) { + try { + const legacyField = await this.fieldService.getField(tableId, fieldId); + if (legacyField.hasError != null) { + field.hasError = legacyField.hasError; + } + } catch (error) { + void error; + } + } + return field; + } return await this.fieldService.getField(tableId, fieldId); } @@ -112,12 +127,16 @@ export class FieldOpenApiController { } @Permissions('field|create') + @UseV2Feature('createField') @Post() async createField( @Param('tableId') tableId: string, @Body(new ZodValidationPipe(createFieldRoSchema)) fieldRo: IFieldRo, @Headers('x-window-id') windowId: string ): Promise { + if (this.cls.get('useV2')) { + return await this.fieldOpenApiV2Service.createField(tableId, fieldRo); + } return await this.fieldOpenApiService.createField(tableId, fieldRo, windowId); } @@ -214,6 +233,7 @@ export class FieldOpenApiController { } @Permissions('field|create') + @UseV2Feature('duplicateField') @Post('/:fieldId/duplicate') async duplicateField( @Param('tableId') tableId: string, @@ -221,6 +241,14 @@ export class FieldOpenApiController { @Body(new ZodValidationPipe(duplicateFieldRoSchema)) duplicateFieldRo: IDuplicateFieldRo, @Headers('x-window-id') windowId: string ) { + if (this.cls.get('useV2')) { + return this.fieldOpenApiV2Service.duplicateField( + tableId, + fieldId, + duplicateFieldRo, + windowId + ); + } return this.fieldOpenApiService.duplicateField(tableId, fieldId, duplicateFieldRo, windowId); } diff --git a/apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts b/apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts index 1b5f9c499..857dbd54e 100644 --- a/apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts +++ b/apps/nestjs-backend/src/features/field/open-api/field-open-api.service.ts @@ -536,10 +536,20 @@ export class FieldOpenApiService { } async getFields(tableId: string, query: IGetFieldsQuery) { - return await this.fieldService.getFieldsByQuery(tableId, { + const fields = await this.fieldService.getFieldsByQuery(tableId, { ...query, filterHidden: query.filterHidden == null ? true : query.filterHidden, }); + + return fields.map((field) => { + if (field.isMultipleCellValue !== false) { + return field; + } + + const normalized = { ...field } as IFieldVo & Record; + delete normalized.isMultipleCellValue; + return normalized as IFieldVo; + }); } private async validateLookupField(field: IFieldInstance) { diff --git a/apps/nestjs-backend/src/features/import/metrics/import-metrics.module.ts b/apps/nestjs-backend/src/features/import/metrics/import-metrics.module.ts index 8256f427e..d0bf5c046 100644 --- a/apps/nestjs-backend/src/features/import/metrics/import-metrics.module.ts +++ b/apps/nestjs-backend/src/features/import/metrics/import-metrics.module.ts @@ -1,8 +1,9 @@ import { Module } from '@nestjs/common'; import { ImportMetricsService } from './import-metrics.service'; +import { ImportTracingService } from './import-tracing.service'; @Module({ - providers: [ImportMetricsService], - exports: [ImportMetricsService], + providers: [ImportMetricsService, ImportTracingService], + exports: [ImportMetricsService, ImportTracingService], }) export class ImportMetricsModule {} diff --git a/apps/nestjs-backend/src/features/import/metrics/import-metrics.service.ts b/apps/nestjs-backend/src/features/import/metrics/import-metrics.service.ts index dc67fb10b..f8cd2e7ae 100644 --- a/apps/nestjs-backend/src/features/import/metrics/import-metrics.service.ts +++ b/apps/nestjs-backend/src/features/import/metrics/import-metrics.service.ts @@ -17,13 +17,6 @@ export class ImportMetricsService { ], }, }); - private readonly importRows = this.meter.createHistogram('data.import.rows', { - description: 'Number of rows per import task', - unit: 'rows', - advice: { - explicitBucketBoundaries: [10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000], - }, - }); private readonly importErrors = this.meter.createCounter('data.import.errors', { description: 'Total number of import errors', }); @@ -38,13 +31,8 @@ export class ImportMetricsService { recordImportComplete(attrs: { fileType: string; operationType: string; - rows: number; durationMs: number; }): void { - this.importRows.record(attrs.rows, { - file_type: attrs.fileType, - operation_type: attrs.operationType, - }); this.importDuration.record(attrs.durationMs, { file_type: attrs.fileType, operation_type: attrs.operationType, diff --git a/apps/nestjs-backend/src/features/import/metrics/import-tracing.service.ts b/apps/nestjs-backend/src/features/import/metrics/import-tracing.service.ts new file mode 100644 index 000000000..b004dee57 --- /dev/null +++ b/apps/nestjs-backend/src/features/import/metrics/import-tracing.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { BaseTracingService } from '../../../tracing/base-tracing.service'; + +@Injectable() +export class ImportTracingService extends BaseTracingService { + setImportAttributes(attrs: { rows: number }): void { + this.withActiveSpan((span) => { + span.setAttribute('data.import.rows', attrs.rows); + }); + } +} diff --git a/apps/nestjs-backend/src/features/import/open-api/import-csv-chunk.processor.ts b/apps/nestjs-backend/src/features/import/open-api/import-csv-chunk.processor.ts index 3d424e52c..bfe193a0c 100644 --- a/apps/nestjs-backend/src/features/import/open-api/import-csv-chunk.processor.ts +++ b/apps/nestjs-backend/src/features/import/open-api/import-csv-chunk.processor.ts @@ -16,6 +16,7 @@ import StorageAdapter from '../../attachments/plugins/adapter'; import { InjectStorageAdapter } from '../../attachments/plugins/storage'; import { NotificationService } from '../../notification/notification.service'; import { ImportMetricsService } from '../metrics/import-metrics.service'; +import { ImportTracingService } from '../metrics/import-tracing.service'; import { ImportTableCsvQueueProcessor, TABLE_IMPORT_CSV_QUEUE } from './import-csv.processor'; import { DEFAULT_IMPORT_CPU_USAGE, getWorkerPath, importerFactory } from './import.class'; @@ -86,7 +87,8 @@ export class ImportTableCsvChunkQueueProcessor extends WorkerHost { private readonly importTableCsvQueueProcessor: ImportTableCsvQueueProcessor, @InjectStorageAdapter() private readonly storageAdapter: StorageAdapter, @InjectQueue(TABLE_IMPORT_CSV_CHUNK_QUEUE) public readonly queue: Queue, - @Optional() private readonly importMetrics?: ImportMetricsService + @Optional() private readonly importMetrics?: ImportMetricsService, + @Optional() private readonly importTracing?: ImportTracingService ) { super(); // When BACKEND_CACHE_REDIS_URI is not set, queues are backed by the local @@ -130,10 +132,10 @@ export class ImportTableCsvChunkQueueProcessor extends WorkerHost { ); const rowCount = await this.resolveDataByWorker(job); this.logger.log(`import data to ${table.id} chunk data job completed`); + this.importTracing?.setImportAttributes({ rows: rowCount }); this.importMetrics?.recordImportComplete({ fileType, operationType, - rows: rowCount, durationMs: Date.now() - importStartTime, }); } catch (error) { diff --git a/apps/nestjs-backend/src/features/record/open-api/record-open-api-v2.service.ts b/apps/nestjs-backend/src/features/record/open-api/record-open-api-v2.service.ts index 4ca692e5b..f57f4f704 100644 --- a/apps/nestjs-backend/src/features/record/open-api/record-open-api-v2.service.ts +++ b/apps/nestjs-backend/src/features/record/open-api/record-open-api-v2.service.ts @@ -690,10 +690,7 @@ export class RecordOpenApiV2Service { const rangeQuery = await this.normalizeRangeQuery(tableId, rangesRo); const normalizedFilter = this.mapV1FilterToV2(rangeQuery.filter); - const sortWithGroupFallback = this.mergeGroupByIntoSort( - rangeQuery.groupBy, - rangeQuery.orderBy - ); + const sortWithGroupFallback = this.mergeGroupByIntoSort(rangeQuery.groupBy, rangeQuery.orderBy); const v2Input = { tableId, viewId: rangeQuery.viewId, @@ -812,10 +809,7 @@ export class RecordOpenApiV2Service { const context = await this.v2ContextFactory.createContext(); const rangeQuery = await this.normalizeRangeQuery(tableId, rangesRo); - const sortWithGroupFallback = this.mergeGroupByIntoSort( - rangeQuery.groupBy, - rangeQuery.orderBy - ); + const sortWithGroupFallback = this.mergeGroupByIntoSort(rangeQuery.groupBy, rangeQuery.orderBy); // Build v2 deleteByRange input const v2Input = { diff --git a/apps/nestjs-backend/src/features/record/record-modify/record-update.service.ts b/apps/nestjs-backend/src/features/record/record-modify/record-update.service.ts index 82bfc80df..d3066c023 100644 --- a/apps/nestjs-backend/src/features/record/record-modify/record-update.service.ts +++ b/apps/nestjs-backend/src/features/record/record-modify/record-update.service.ts @@ -62,6 +62,7 @@ export class RecordUpdateService { updateRecordsRo: IUpdateRecordsInternalRo, windowId?: string ) { + const effectiveWindowId = windowId ?? this.cls.get('windowId'); const { records, order, @@ -73,7 +74,7 @@ export class RecordUpdateService { const table = await this.tableDomainQueryService.getTableDomainById(tableId); const scopedRecords = this.filterRecordsByFieldKeys(records, fieldIds); const orderIndexesBefore = - order != null && windowId + order != null && effectiveWindowId ? await this.recordService.getRecordIndexes( table, records.map((r) => r.id), @@ -145,13 +146,13 @@ export class RecordUpdateService { }); const recordIds = records.map((r) => r.id); - if (windowId) { + if (effectiveWindowId) { const orderIndexesAfter = order && (await this.recordService.getRecordIndexes(table, recordIds, order.viewId)); this.eventEmitterService.emitAsync(Events.OPERATION_RECORDS_UPDATE, { tableId, - windowId, + windowId: effectiveWindowId, userId: this.cls.get('user.id'), recordIds, fieldIds: fieldIds?.length ? fieldIds : Object.keys(scopedRecords[0]?.fields || {}), diff --git a/apps/nestjs-backend/src/features/selection/selection.service.ts b/apps/nestjs-backend/src/features/selection/selection.service.ts index 3eb6afacb..189c2f7a8 100644 --- a/apps/nestjs-backend/src/features/selection/selection.service.ts +++ b/apps/nestjs-backend/src/features/selection/selection.service.ts @@ -757,6 +757,7 @@ export class SelectionService { windowId?: string; } = {} ) { + const effectiveWindowId = windowId ?? this.cls.get('windowId'); const { content, header, ...rangesRo } = pasteRo; const { ranges, type, ...queryRo } = rangesRo; const { viewId } = queryRo; @@ -911,9 +912,9 @@ export class SelectionService { }; }); - if (windowId) { + if (effectiveWindowId) { this.eventEmitterService.emitAsync(Events.OPERATION_PASTE_SELECTION, { - windowId, + windowId: effectiveWindowId, userId: this.cls.get('user.id'), tableId, updateRecords, diff --git a/apps/nestjs-backend/src/features/undo-redo/operations/paste-selection.operation.ts b/apps/nestjs-backend/src/features/undo-redo/operations/paste-selection.operation.ts index f9f5a1304..6fbe319ba 100644 --- a/apps/nestjs-backend/src/features/undo-redo/operations/paste-selection.operation.ts +++ b/apps/nestjs-backend/src/features/undo-redo/operations/paste-selection.operation.ts @@ -71,13 +71,6 @@ export class PasteSelectionOperation { }); } - if (newRecords && newRecords.length > 0) { - await this.recordOpenApiService.deleteRecords( - tableId, - newRecords.map((r) => r.id) - ); - } - if (newFields && newFields.length > 0) { await this.fieldOpenApiService.deleteFields( tableId, @@ -85,6 +78,13 @@ export class PasteSelectionOperation { ); } + if (newRecords && newRecords.length > 0) { + await this.recordOpenApiService.deleteRecords( + tableId, + newRecords.map((r) => r.id) + ); + } + return operation; } diff --git a/apps/nestjs-backend/src/features/v2/v2-undo-redo.service.ts b/apps/nestjs-backend/src/features/v2/v2-undo-redo.service.ts index 834cd675f..f099bb704 100644 --- a/apps/nestjs-backend/src/features/v2/v2-undo-redo.service.ts +++ b/apps/nestjs-backend/src/features/v2/v2-undo-redo.service.ts @@ -1,7 +1,16 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { Injectable, Logger } from '@nestjs/common'; -import type { IFieldVo, IOtOperation, IRecord } from '@teable/core'; import { + CellValueType, + FieldType, + getDbFieldType, + type IColumnMeta, + type IFieldVo, + type IOtOperation, + type IRecord, +} from '@teable/core'; +import { + FieldCreated, FieldUpdated, ProjectionHandler, RecordReordered, @@ -17,6 +26,7 @@ import { import type { DomainError, IEventHandler, IExecutionContext, Result } from '@teable/v2-core'; import type { DependencyContainer } from '@teable/v2-di'; import { + type ICreateFieldsOperation, OperationName, type IConvertFieldV2Operation, type ICreateRecordsOperation, @@ -157,6 +167,72 @@ const mergeOpsMap = (base: IOpsMap | undefined, patch: IOpsMap): IOpsMap => { return result; }; +const deriveCellValueType = (field: IFieldVo): CellValueType => { + switch (field.type) { + case FieldType.Number: + case FieldType.Rating: + case FieldType.AutoNumber: + return CellValueType.Number; + case FieldType.Checkbox: + return CellValueType.Boolean; + case FieldType.Date: + case FieldType.CreatedTime: + case FieldType.LastModifiedTime: + return CellValueType.DateTime; + default: + return CellValueType.String; + } +}; + +const deriveIsMultipleCellValue = (field: IFieldVo): boolean => { + switch (field.type) { + case FieldType.MultipleSelect: + case FieldType.Attachment: + return true; + case FieldType.Link: { + const options = + field.options && typeof field.options === 'object' && !Array.isArray(field.options) + ? (field.options as Record) + : undefined; + const relationship = options?.relationship; + return relationship === 'oneMany' || relationship === 'manyMany'; + } + case FieldType.User: { + const options = + field.options && typeof field.options === 'object' && !Array.isArray(field.options) + ? (field.options as Record) + : undefined; + return options?.isMultiple === true; + } + default: + return false; + } +}; + +const normalizeUndoField = (field: IFieldVo): IFieldVo => { + const normalized: IFieldVo = { + ...field, + }; + + if (normalized.cellValueType == null) { + normalized.cellValueType = deriveCellValueType(normalized); + } + + if (normalized.isMultipleCellValue == null && deriveIsMultipleCellValue(normalized)) { + normalized.isMultipleCellValue = true; + } + + if (normalized.dbFieldType == null && normalized.cellValueType != null) { + normalized.dbFieldType = getDbFieldType( + normalized.type as FieldType, + normalized.cellValueType, + normalized.isMultipleCellValue + ); + } + + return normalized; +}; + const buildModifiedOps = ( tableId: string, fieldId: string, @@ -419,6 +495,74 @@ class V2RecordsBatchUpdatedUndoRedoProjection implements IEventHandler { + constructor( + private readonly undoRedoStackService: UndoRedoStackService, + private readonly tableQueryService: TableQueryService, + private readonly tableMapper: ITableMapper + ) {} + + async handle( + context: IExecutionContext, + event: FieldCreated + ): Promise> { + const { windowId, actorId } = context; + + if (!windowId) { + return ok(undefined); + } + + const tableId = event.tableId.toString(); + const userId = actorId.toString(); + const fieldId = event.fieldId.toString(); + + const tableResult = await this.tableQueryService.getById(context, event.tableId); + if (tableResult.isErr()) { + return ok(undefined); + } + + const tableDtoResult = this.tableMapper.toDTO(tableResult.value); + if (tableDtoResult.isErr()) { + return ok(undefined); + } + + const createdField = tableDtoResult.value.fields.find((field) => field.id === fieldId); + if (!createdField) { + return ok(undefined); + } + + const eventColumnMeta = Object.fromEntries( + Object.entries(event.viewOrders ?? {}).map(([viewId, order]) => [viewId, { order }]) + ) as IColumnMeta; + const fallbackColumnMeta = Object.fromEntries( + tableDtoResult.value.views.flatMap((view) => { + const column = (view.columnMeta as Record | undefined)?.[fieldId]; + return column == null ? [] : [[view.id, column]]; + }) + ) as IColumnMeta; + const normalizedColumnMeta = + Object.keys(eventColumnMeta).length > 0 ? eventColumnMeta : fallbackColumnMeta; + const createdFieldWithMeta: IFieldVo & { columnMeta?: IColumnMeta } = { + ...normalizeUndoField(createdField as unknown as IFieldVo), + ...(Object.keys(normalizedColumnMeta).length > 0 ? { columnMeta: normalizedColumnMeta } : {}), + }; + + const operation: ICreateFieldsOperation = { + name: OperationName.CreateFields, + params: { + tableId, + }, + result: { + fields: [createdFieldWithMeta], + }, + }; + + await this.undoRedoStackService.push(userId, tableId, windowId, operation); + return ok(undefined); + } +} + /** * V2 projection handler that captures field type-conversion events and pushes * convert-field operations to undo/redo stack. @@ -775,6 +919,11 @@ export class V2UndoRedoService { ) ); + container.registerInstance( + V2FieldCreatedUndoRedoProjection, + new V2FieldCreatedUndoRedoProjection(undoRedoStackService, tableQueryService, tableMapper) + ); + container.registerInstance( V2RecordReorderedUndoRedoProjection, new V2RecordReorderedUndoRedoProjection(undoRedoStackService) diff --git a/apps/nestjs-backend/src/tracing.ts b/apps/nestjs-backend/src/tracing.ts index dca79b3b3..fa4cf615b 100644 --- a/apps/nestjs-backend/src/tracing.ts +++ b/apps/nestjs-backend/src/tracing.ts @@ -63,7 +63,7 @@ const nativeRequire: NodeRequire = typeof __non_webpack_require__ !== 'undefined' ? __non_webpack_require__ : require; const { BatchLogRecordProcessor } = opentelemetry.logs; -const { PeriodicExportingMetricReader } = opentelemetry.metrics; +const { PeriodicExportingMetricReader, AggregationType } = opentelemetry.metrics; const { AlwaysOnSampler } = opentelemetry.node; const otelLogger = new Logger('OpenTelemetry'); @@ -160,6 +160,32 @@ const metricsExporter = metricsEndpoint ? new OTLPMetricExporter(createExporterOptions(metricsEndpoint)) : undefined; +// Strip high-cardinality resource attributes from metrics only. +// Traces and logs keep these for debugging; metrics drop them to prevent +// cardinality explosion in ephemeral containers (each restart = new host.name + pid). +if (metricsExporter) { + const dropFromMetricResource = new Set([ + 'host.name', + 'host.arch', + 'os.type', + 'os.description', + 'process.pid', + 'process.command', + 'process.command_args', + 'process.command_line', + 'process.executable.path', + 'process.owner', + 'service.instance.id', + ]); + const origExport = metricsExporter.export.bind(metricsExporter); + metricsExporter.export = (metrics, cb) => { + const attrs = Object.fromEntries( + Object.entries(metrics.resource.attributes).filter(([k]) => !dropFromMetricResource.has(k)) + ); + origExport({ ...metrics, resource: resourceFromAttributes(attrs) }, cb); + }; +} + // Smart export: deterministic decision based on traceId hash // No cache needed - hash function is pure and fast const getTraceDecision = (traceId: string): boolean => { @@ -263,12 +289,21 @@ const ignorePaths = [ '/health', ]; +// Drop old semconv HTTP metrics — new semconv (http.*.request.duration) is used in all dashboards; +// the old names (http.server.duration, http.client.duration) are pure duplicates with high cardinality. +const dropAggregation = { type: AggregationType.DROP } as const; +const metricViews = [ + { instrumentName: 'http.server.duration', aggregation: dropAggregation }, + { instrumentName: 'http.client.duration', aggregation: dropAggregation }, +]; + const otelSDK = new opentelemetry.NodeSDK({ spanProcessors, logRecordProcessors: logExporter ? [new BatchLogRecordProcessor(logExporter)] : [], sampler: new AlwaysOnSampler(), contextManager: SentryContextManager ? new SentryContextManager() : undefined, textMapPropagator: hasSentry ? new SentryPropagator() : undefined, + views: metricViews, metricReader: metricsExporter ? new PeriodicExportingMetricReader({ exporter: metricsExporter, diff --git a/apps/nestjs-backend/src/tracing/base-tracing.service.ts b/apps/nestjs-backend/src/tracing/base-tracing.service.ts new file mode 100644 index 000000000..4f95f8f61 --- /dev/null +++ b/apps/nestjs-backend/src/tracing/base-tracing.service.ts @@ -0,0 +1,17 @@ +import { Logger } from '@nestjs/common'; +import type { Span } from '@opentelemetry/api'; +import { trace } from '@opentelemetry/api'; + +export abstract class BaseTracingService { + protected readonly logger = new Logger(this.constructor.name); + + protected withActiveSpan(fn: (span: Span) => void): void { + try { + const span = trace.getActiveSpan(); + if (!span) return; + fn(span); + } catch (e) { + this.logger.warn(`Tracing failed: ${e}`); + } + } +} diff --git a/apps/nestjs-backend/src/types/i18n.generated.ts b/apps/nestjs-backend/src/types/i18n.generated.ts index 66c983362..1959b773e 100644 --- a/apps/nestjs-backend/src/types/i18n.generated.ts +++ b/apps/nestjs-backend/src/types/i18n.generated.ts @@ -255,6 +255,7 @@ export type I18nTranslations = { "copySuccess": string; "retry": string; "copyToMySpace": string; + "copyLink": string; "collapse": string; "viewDetails": string; }; diff --git a/apps/nestjs-backend/test/field-duplicate.e2e-spec.ts b/apps/nestjs-backend/test/field-duplicate.e2e-spec.ts index 35847ead4..a647aeb83 100644 --- a/apps/nestjs-backend/test/field-duplicate.e2e-spec.ts +++ b/apps/nestjs-backend/test/field-duplicate.e2e-spec.ts @@ -104,6 +104,148 @@ describe('OpenAPI FieldOpenApiController for duplicate field (e2e)', () => { }); }); + describe('duplicate field response compatibility under FORCE_V2', () => { + let table: ITableFullVo; + let foreignTable: ITableFullVo; + let linkFieldId: string; + let foreignPrimaryFieldId: string; + + beforeAll(async () => { + foreignTable = await createTable(baseId, { + name: 'dup_force_v2_compat_foreign', + fields: [ + { + type: FieldType.SingleLineText, + name: 'foreign_name', + }, + ], + }); + foreignPrimaryFieldId = foreignTable.fields.find((f) => f.isPrimary)!.id; + + table = await createTable(baseId, { + name: 'dup_force_v2_compat_main', + }); + + const linkField = ( + await createField(table.id, { + type: FieldType.Link, + name: 'to_foreign', + options: { + relationship: Relationship.ManyMany, + foreignTableId: foreignTable.id, + isOneWay: false, + }, + }) + ).data; + linkFieldId = linkField.id; + }); + + afterAll(async () => { + await permanentDeleteTable(baseId, table.id); + await permanentDeleteTable(baseId, foreignTable.id); + }); + + it('keeps description but omits false/linked compatibility keys in duplicated fields', async () => { + const describedField = ( + await createField(table.id, { + type: FieldType.Number, + name: 'number_with_description', + description: 'description_kept', + }) + ).data; + const duplicatedDescribedField = ( + await duplicateField(table.id, describedField.id, { + name: 'number_with_description_copy', + }) + ).data; + expect(duplicatedDescribedField.description).toBe('description_kept'); + + const lookupField = ( + await createField(table.id, { + type: FieldType.SingleLineText, + name: 'lookup_force_v2_compat', + isLookup: true, + lookupOptions: { + foreignTableId: foreignTable.id, + linkFieldId, + lookupFieldId: foreignPrimaryFieldId, + }, + }) + ).data; + const duplicatedLookupField = ( + await duplicateField(table.id, lookupField.id, { + name: 'lookup_force_v2_compat_copy', + }) + ).data; + const duplicatedLookupOptions = duplicatedLookupField.lookupOptions as + | Record + | undefined; + + expect(Object.prototype.hasOwnProperty.call(duplicatedLookupOptions ?? {}, 'isOneWay')).toBe( + false + ); + expect( + Object.prototype.hasOwnProperty.call(duplicatedLookupOptions ?? {}, 'symmetricFieldId') + ).toBe(false); + + const rollupField = ( + await createField(table.id, { + type: FieldType.Rollup, + name: 'rollup_force_v2_compat', + lookupOptions: { + foreignTableId: foreignTable.id, + linkFieldId, + lookupFieldId: foreignPrimaryFieldId, + }, + options: { + expression: 'countall({values})', + }, + }) + ).data; + const duplicatedRollupField = ( + await duplicateField(table.id, rollupField.id, { + name: 'rollup_force_v2_compat_copy', + }) + ).data; + const duplicatedRollupLookupOptions = duplicatedRollupField.lookupOptions as + | Record + | undefined; + + expect( + Object.prototype.hasOwnProperty.call(duplicatedRollupLookupOptions ?? {}, 'isOneWay') + ).toBe(false); + expect( + Object.prototype.hasOwnProperty.call( + duplicatedRollupLookupOptions ?? {}, + 'symmetricFieldId' + ) + ).toBe(false); + + const buttonField = ( + await createField(table.id, { + type: FieldType.Button, + name: 'button_force_v2_compat', + options: { + label: 'go', + color: Colors.Blue, + workflow: { + id: generateWorkflowId(), + name: 'wf_for_compat', + isActive: true, + }, + }, + }) + ).data; + const duplicatedButtonField = ( + await duplicateField(table.id, buttonField.id, { + name: 'button_force_v2_compat_copy', + }) + ).data; + + expect(duplicatedButtonField.isMultipleCellValue).toBeUndefined(); + }); + }); + afterAll(async () => { await app.close(); }); diff --git a/apps/nestjs-backend/test/formula.e2e-spec.ts b/apps/nestjs-backend/test/formula.e2e-spec.ts index 2c98c4f8c..1ff91261f 100644 --- a/apps/nestjs-backend/test/formula.e2e-spec.ts +++ b/apps/nestjs-backend/test/formula.e2e-spec.ts @@ -3132,7 +3132,7 @@ describe('OpenAPI formula (e2e)', () => { } await permanentDeleteTable(baseId, foreign.id); } - }); + }, 120000); it('applies timezone-aware formatting before slicing datetime values', async () => { const foreign = await createTable(baseId, { diff --git a/apps/nestjs-backend/test/integrity.e2e-spec.ts b/apps/nestjs-backend/test/integrity.e2e-spec.ts index af867b9cb..d6431469a 100644 --- a/apps/nestjs-backend/test/integrity.e2e-spec.ts +++ b/apps/nestjs-backend/test/integrity.e2e-spec.ts @@ -538,7 +538,6 @@ describe('OpenAPI integrity (e2e)', () => { await executeKnex( knex.schema.alterTable(options.fkHostTableName, (table) => { - table.dropForeign(options.foreignKeyName, `fk_${options.foreignKeyName}`); table.dropColumn(options.foreignKeyName); table.dropColumn(`${options.foreignKeyName}_order`); }) @@ -591,7 +590,6 @@ describe('OpenAPI integrity (e2e)', () => { await executeKnex( knex.schema.alterTable(options.fkHostTableName, (table) => { - table.dropForeign(options.foreignKeyName, `fk_${options.foreignKeyName}`); table.dropColumn(options.foreignKeyName); }) ); @@ -638,7 +636,6 @@ describe('OpenAPI integrity (e2e)', () => { await executeKnex( knex.schema.alterTable(options.fkHostTableName, (table) => { - table.dropForeign(options.selfKeyName, `fk_${options.selfKeyName}`); table.dropColumn(options.selfKeyName); }) ); diff --git a/apps/nestjs-backend/test/lookup.e2e-spec.ts b/apps/nestjs-backend/test/lookup.e2e-spec.ts index 87f1d99d5..2b961ec0c 100644 --- a/apps/nestjs-backend/test/lookup.e2e-spec.ts +++ b/apps/nestjs-backend/test/lookup.e2e-spec.ts @@ -879,7 +879,6 @@ describe('OpenAPI Lookup field (e2e)', () => { ); expect(sourceRecord).toBeTruthy(); expect(hostRecord).toBeTruthy(); - expect(hostRecord!.fields[HOST_LOOKUP_AUTO]).toEqual(sourceRecord!.fields[SOURCE_AUTO_FIELD]); expect(normalizeSingle(hostRecord!.fields[HOST_LOOKUP_CREATED_TIME] as unknown)).toEqual( sourceRecord!.fields[SOURCE_CREATED_TIME_FIELD] diff --git a/apps/nestjs-backend/test/utils/event-promise.ts b/apps/nestjs-backend/test/utils/event-promise.ts index 44a186df4..14c4833fc 100644 --- a/apps/nestjs-backend/test/utils/event-promise.ts +++ b/apps/nestjs-backend/test/utils/event-promise.ts @@ -16,9 +16,9 @@ export function createEventPromise(eventEmitterService: EventEmitterService, eve } export function createAwaitWithEvent(eventEmitterService: EventEmitterService, event: Events) { - return async function fn(fn: () => Promise) { + return async function runWithEvent(action: () => Promise) { const promise = createEventPromise(eventEmitterService, event); - const result = await fn(); + const result = await action(); await promise; return result; }; @@ -28,9 +28,9 @@ export function createAwaitWithEventWithResult( eventEmitterService: EventEmitterService, event: Events ) { - return async function fn(fn: () => Promise) { + return async function runWithEventResult(action: () => Promise) { const promise = createEventPromise(eventEmitterService, event); - await fn(); + await action(); await promise; return (await promise) as R; }; @@ -62,9 +62,9 @@ export function createAwaitWithEventWithResultWithCount( event: Events, count: number = 1 ) { - return async function fn(fn: () => Promise) { + return async function runWithEventResultCount(action: () => Promise) { const promise = createEventPromiseWithCount(eventEmitterService, event, count); - const result = await fn(); + const result = await action(); const payloads = await promise; return { result, diff --git a/apps/nextjs-app/src/features/app/blocks/table/table-header/TableHeader.tsx b/apps/nextjs-app/src/features/app/blocks/table/table-header/TableHeader.tsx index e589370e8..1e1dd4078 100644 --- a/apps/nextjs-app/src/features/app/blocks/table/table-header/TableHeader.tsx +++ b/apps/nextjs-app/src/features/app/blocks/table/table-header/TableHeader.tsx @@ -1,4 +1,4 @@ -import { HelpCircle, MoreHorizontal, UserPlus } from '@teable/icons'; +import { Copy, HelpCircle, MoreHorizontal, UserPlus } from '@teable/icons'; import { BaseNodeResourceType } from '@teable/openapi'; import { useBase, @@ -21,6 +21,7 @@ import { SheetHeader, SheetTrigger, } from '@teable/ui-lib/shadcn'; +import { toast } from '@teable/ui-lib/shadcn/ui/sonner'; import Link from 'next/link'; import { useRouter } from 'next/router'; @@ -30,6 +31,7 @@ import { ShareBasePopover } from '@/features/app/components/collaborator/share/S import { PublicOperateButton } from '@/features/app/components/PublicOperateButton'; import type { IBaseResourceTable } from '@/features/app/hooks/useBaseResource'; import { useBaseResource } from '@/features/app/hooks/useBaseResource'; +import { useIsInIframe } from '@/features/app/hooks/useIsInIframe'; import { tableConfig } from '@/features/i18n/table.config'; import { BaseNodeMore } from '../../base/base-side-bar/BaseNodeMore'; import { ExpandViewList } from '../../view/list/ExpandViewList'; @@ -208,12 +210,14 @@ const RightActions = ({ setIsEditing }: { setIsEditing?: (isEditing: boolean) => }; export const TableHeader: React.FC = () => { + const { t } = useTranslation(tableConfig.i18nNamespaces); const view = useView(); const { visible } = useLockedViewTipStore(); const isReadOnlyPreview = useIsReadOnlyPreview(); const template = useTemplate(); + const isInIframe = useIsInIframe(); // Only show PublicOperateButton for real templates, not for share mode - const isRealTemplate = !!template; + const isRealTemplate = !!template && !isInIframe; const tipVisible = view?.isLocked && visible; const [isEditing, setIsEditing] = useState(false); return ( @@ -236,7 +240,20 @@ export const TableHeader: React.FC = () => {
{!isReadOnlyPreview && } {isRealTemplate && ( -
+
+
)} diff --git a/apps/nextjs-app/src/features/app/components/collaborator-manage/components/InviteLinkItem.tsx b/apps/nextjs-app/src/features/app/components/collaborator-manage/components/InviteLinkItem.tsx index b4713e6a3..a53f6f51f 100644 --- a/apps/nextjs-app/src/features/app/components/collaborator-manage/components/InviteLinkItem.tsx +++ b/apps/nextjs-app/src/features/app/components/collaborator-manage/components/InviteLinkItem.tsx @@ -1,9 +1,8 @@ -import { Copy, X } from '@teable/icons'; +import { Copy, Trash2 } from '@teable/icons'; import { useLanDayjs } from '@teable/sdk/hooks'; import { syncCopy } from '@teable/sdk/utils'; import { Button, - Input, Tooltip, TooltipContent, TooltipProvider, @@ -29,36 +28,46 @@ export const InviteLinkItem = (props: { }; return ( -
-
- - -
-
- {t('invite.dialog.linkCreatedTime', { createdTime: dayjs(createdTime).fromNow() })} +
+
+
{url}
+
+ {dayjs(createdTime).format('YYYY-MM-DD')} +
{children} - - - - - - -

{t('invite.dialog.linkRemove')}

-
-
-
+
+ + + + + + +

{t('actions.copyLink')}

+
+
+
+ + + + + + +

{t('invite.dialog.linkRemove')}

+
+
+
+
); }; diff --git a/packages/common-i18n/src/locales/de/sdk.json b/packages/common-i18n/src/locales/de/sdk.json index 89aeec601..05f839486 100644 --- a/packages/common-i18n/src/locales/de/sdk.json +++ b/packages/common-i18n/src/locales/de/sdk.json @@ -660,7 +660,7 @@ "example": "TONOW({Date}, \"day\") => 25" }, "DATETIME_DIFF": { - "summary": "Gibt die Differenz zwischen den Zeitpunkten in den angegebenen Einheiten zurück. Standardeinheiten sind Sekunden. (Siehe Liste der Einheitenspezifikationen hier.)\nDie Differenz zwischen Datumszeiten wird durch Subtraktion von [datum2] von [datum1] ermittelt. Das bedeutet, dass der resultierende Wert negativ ist, wenn [datum2] später als [datum1] liegt.", + "summary": "Gibt die Differenz zwischen den Zeitpunkten in den angegebenen Einheiten zurück. Standardeinheit ist \"day\".\nUnterstützte Einheiten: \"millisecond\" (ms), \"second\" (s), \"minute\" (m), \"hour\" (h), \"day\" (d), \"week\" (w), \"month\" (M), \"year\" (y).\nDie Differenz zwischen Datumszeiten wird durch Subtraktion von [datum2] von [datum1] ermittelt. Das bedeutet, dass der resultierende Wert negativ ist, wenn [datum2] später als [datum1] liegt.", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/en/common.json b/packages/common-i18n/src/locales/en/common.json index 7d66681d8..786143ebd 100644 --- a/packages/common-i18n/src/locales/en/common.json +++ b/packages/common-i18n/src/locales/en/common.json @@ -63,6 +63,7 @@ "login": "Login", "useTemplate": "Use template", "copyToMySpace": "Copy to my space", + "copyLink": "Copy link", "backToSpace": "Back to space", "switchBase": "Switch base", "collapse": "Collapse", diff --git a/packages/common-i18n/src/locales/en/sdk.json b/packages/common-i18n/src/locales/en/sdk.json index 6624a005f..f558e18af 100644 --- a/packages/common-i18n/src/locales/en/sdk.json +++ b/packages/common-i18n/src/locales/en/sdk.json @@ -677,7 +677,7 @@ "example": "TONOW({Date}, \"day\") => 25" }, "DATETIME_DIFF": { - "summary": "Returns the difference between datetimes in specified units. Default units are seconds. (See list of unit specifiers here.)\nThe difference between datetimes is determined by subtracting [date2] from [date1]. This means that if [date2] is later than [date1], the resulting value will be negative.", + "summary": "Returns the difference between datetimes in specified units. Default unit is \"day\".\nSupported units: \"millisecond\" (ms), \"second\" (s), \"minute\" (m), \"hour\" (h), \"day\" (d), \"week\" (w), \"month\" (M), \"year\" (y).\nThe difference between datetimes is determined by subtracting [date2] from [date1]. This means that if [date2] is later than [date1], the resulting value will be negative.", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/es/sdk.json b/packages/common-i18n/src/locales/es/sdk.json index 58d557303..9f2cbf2e7 100644 --- a/packages/common-i18n/src/locales/es/sdk.json +++ b/packages/common-i18n/src/locales/es/sdk.json @@ -664,7 +664,7 @@ "example": "Tonow ({date}, \"día\") => 25" }, "DATETIME_DIFF": { - "summary": "Devuelve la diferencia entre datos en unidades especificadas. ", + "summary": "Devuelve la diferencia entre fechas en unidades especificadas. La unidad predeterminada es \"day\".\nUnidades soportadas: \"millisecond\" (ms), \"second\" (s), \"minute\" (m), \"hour\" (h), \"day\" (d), \"week\" (w), \"month\" (M), \"year\" (y).\nLa diferencia entre fechas se determina restando [date2] de [date1]. Esto significa que si [date2] es posterior a [date1], el valor resultante será negativo.", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/fr/sdk.json b/packages/common-i18n/src/locales/fr/sdk.json index 3e42abf5e..ac6842c30 100644 --- a/packages/common-i18n/src/locales/fr/sdk.json +++ b/packages/common-i18n/src/locales/fr/sdk.json @@ -660,7 +660,7 @@ "example": "TONOW({Date}, \"day\") => 25" }, "DATETIME_DIFF": { - "summary": "Renvoie la différence entre les datetimes dans les unités spécifiées. Les unités par défaut sont les secondes. (Voir la liste des spécificateurs d'unité ici.)\nLa différence entre les datetimes est déterminée en soustrayant [date2] de [date1]. Cela signifie que si [date2] est plus tard que [date1], la valeur résultante sera négative.", + "summary": "Renvoie la différence entre les datetimes dans les unités spécifiées. L'unité par défaut est \"day\".\nUnités supportées : \"millisecond\" (ms), \"second\" (s), \"minute\" (m), \"hour\" (h), \"day\" (d), \"week\" (w), \"month\" (M), \"year\" (y).\nLa différence entre les datetimes est déterminée en soustrayant [date2] de [date1]. Cela signifie que si [date2] est plus tard que [date1], la valeur résultante sera négative.", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/it/sdk.json b/packages/common-i18n/src/locales/it/sdk.json index f4abb65fc..8e7d56fd9 100644 --- a/packages/common-i18n/src/locales/it/sdk.json +++ b/packages/common-i18n/src/locales/it/sdk.json @@ -660,7 +660,7 @@ "example": "TONOW({Date}, \"day\") => 25" }, "DATETIME_DIFF": { - "summary": "Restituisce la differenza tra le date in unità specificate. Le unità predefinite sono i secondi. (Vedi l'elenco dei specificatori di unità qui.)\nLa differenza tra le date è determinata sottraendo [date2] da [date1]. Ciò significa che se [date2] è successiva a [date1], il valore risultante sarà negativo.", + "summary": "Restituisce la differenza tra le date in unità specificate. L'unità predefinita è \"day\".\nUnità supportate: \"millisecond\" (ms), \"second\" (s), \"minute\" (m), \"hour\" (h), \"day\" (d), \"week\" (w), \"month\" (M), \"year\" (y).\nLa differenza tra le date è determinata sottraendo [date2] da [date1]. Ciò significa che se [date2] è successiva a [date1], il valore risultante sarà negativo.", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/ja/sdk.json b/packages/common-i18n/src/locales/ja/sdk.json index 8c9fab6e4..1a7a6204b 100644 --- a/packages/common-i18n/src/locales/ja/sdk.json +++ b/packages/common-i18n/src/locales/ja/sdk.json @@ -660,7 +660,7 @@ "example": "TONOW({Date}, \"day\") => 25" }, "DATETIME_DIFF": { - "summary": "指定された単位で日付時刻の差を返します。デフォルトの単位は秒です。(単位指定子のリストはここを参照してください。)\n日付時刻の差は、[date1] から [date2] を減算して決定されます。つまり、[date2] が [date1] より後の場合、結果の値は負になります。", + "summary": "指定された単位で日付時刻の差を返します。デフォルトの単位は \"day\" です。\nサポートされている単位: \"millisecond\" (ms)、\"second\" (s)、\"minute\" (m)、\"hour\" (h)、\"day\" (d)、\"week\" (w)、\"month\" (M)、\"year\" (y)。\n日付時刻の差は、[date1] から [date2] を減算して決定されます。つまり、[date2] が [date1] より後の場合、結果の値は負になります。", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/ru/sdk.json b/packages/common-i18n/src/locales/ru/sdk.json index cfab485e2..acf41ebca 100644 --- a/packages/common-i18n/src/locales/ru/sdk.json +++ b/packages/common-i18n/src/locales/ru/sdk.json @@ -660,7 +660,7 @@ "example": "TONOW({Date}, \"день\") => 25" }, "DATETIME_DIFF": { - "summary": "Возвращает разницу между датами в указанных единицах. По умолчанию — в секундах.", + "summary": "Возвращает разницу между датами в указанных единицах. Единица по умолчанию — \"day\".\nПоддерживаемые единицы: \"millisecond\" (ms), \"second\" (s), \"minute\" (m), \"hour\" (h), \"day\" (d), \"week\" (w), \"month\" (M), \"year\" (y).\nРазница между датами определяется путём вычитания [date2] из [date1]. Это означает, что если [date2] позже [date1], результат будет отрицательным.", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/tr/sdk.json b/packages/common-i18n/src/locales/tr/sdk.json index 3f8301389..b7332e89e 100644 --- a/packages/common-i18n/src/locales/tr/sdk.json +++ b/packages/common-i18n/src/locales/tr/sdk.json @@ -660,7 +660,7 @@ "example": "TONOW({Date}, \"day\") => 25" }, "DATETIME_DIFF": { - "summary": "Tarih/saatler arasındaki farkı belirtilen birimde döndürür. Varsayılan birim saniyedir. (Birim belirteçlerinin listesi için buraya bakın.)\nTarih/saatler arasındaki fark [date2]'nin [date1]'den çıkarılmasıyla belirlenir. Bu, eğer [date2] [date1]'den sonraysa, sonuç değerinin negatif olacağı anlamına gelir.", + "summary": "Tarih/saatler arasındaki farkı belirtilen birimde döndürür. Varsayılan birim \"day\"dir.\nDesteklenen birimler: \"millisecond\" (ms), \"second\" (s), \"minute\" (m), \"hour\" (h), \"day\" (d), \"week\" (w), \"month\" (M), \"year\" (y).\nTarih/saatler arasındaki fark [date2]'nin [date1]'den çıkarılmasıyla belirlenir. Bu, eğer [date2] [date1]'den sonraysa, sonuç değerinin negatif olacağı anlamına gelir.", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/uk/sdk.json b/packages/common-i18n/src/locales/uk/sdk.json index 1a3d69bdc..808541b4a 100644 --- a/packages/common-i18n/src/locales/uk/sdk.json +++ b/packages/common-i18n/src/locales/uk/sdk.json @@ -660,7 +660,7 @@ "example": "TONOW({Date}, \"day\") => 25" }, "DATETIME_DIFF": { - "summary": "Повертає різницю між датою та часом у вказаних одиницях. Одиницями за замовчуванням є секунди. (Див. список специфікаторів одиниць тут.)\nРізниця між датою та часом визначається шляхом віднімання [date2] від [date1]. Це означає, що якщо [date2] пізніше [date1], результуюче значення буде від’ємним.", + "summary": "Повертає різницю між датою та часом у вказаних одиницях. Одиниця за замовчуванням — \"day\".\nПідтримувані одиниці: \"millisecond\" (ms), \"second\" (s), \"minute\" (m), \"hour\" (h), \"day\" (d), \"week\" (w), \"month\" (M), \"year\" (y).\nРізниця між датою та часом визначається шляхом віднімання [date2] від [date1]. Це означає, що якщо [date2] пізніше [date1], результуюче значення буде від'ємним.", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/common-i18n/src/locales/zh/common.json b/packages/common-i18n/src/locales/zh/common.json index 97156a6a6..9db72f0ba 100644 --- a/packages/common-i18n/src/locales/zh/common.json +++ b/packages/common-i18n/src/locales/zh/common.json @@ -63,6 +63,7 @@ "login": "登录", "useTemplate": "使用模版", "copyToMySpace": "复制到我的空间", + "copyLink": "复制链接", "backToSpace": "返回空间", "switchBase": "切换数据库", "collapse": "收起", diff --git a/packages/common-i18n/src/locales/zh/sdk.json b/packages/common-i18n/src/locales/zh/sdk.json index 1ed2cf759..d9d9b4d00 100644 --- a/packages/common-i18n/src/locales/zh/sdk.json +++ b/packages/common-i18n/src/locales/zh/sdk.json @@ -677,7 +677,7 @@ "example": "TONOW({Date}, \"day\") => 25" }, "DATETIME_DIFF": { - "summary": "以指定的单位返回日期时间之间的差异。默认单位为秒。(单位说明符列表请点击此处。)\n日期时间之间的差异是通过从 [date1] 减去 [date2] 来确定的。这意味着如果 [date2] 晚于 [date1],结果值将为负数。", + "summary": "以指定的单位返回日期时间之间的差异。默认单位为 \"day\"。\n支持的单位:\"millisecond\" (ms)、\"second\" (s)、\"minute\" (m)、\"hour\" (h)、\"day\" (d)、\"week\" (w)、\"month\" (M)、\"year\" (y)。\n日期时间之间的差异是通过从 [date1] 减去 [date2] 来确定的。这意味着如果 [date2] 晚于 [date1],结果值将为负数。", "example": "DATETIME_DIFF(\"2023-09-08\", \"2022-08-01\", \"day\") => 403" }, "WORKDAY": { diff --git a/packages/core/src/errors/extract-error-message.ts b/packages/core/src/errors/extract-error-message.ts new file mode 100644 index 000000000..be28133d8 --- /dev/null +++ b/packages/core/src/errors/extract-error-message.ts @@ -0,0 +1,58 @@ +/** + * Safely extract a human-readable message from any thrown value. + * + * Handles all common shapes: + * - `Error` instances → error.message + * - plain strings → the string itself + * - objects with message/error → the string field + * - nested { error: { message } } → the nested message + * - { responseBody: '{"error":{"message":"..."}}' } → parsed body message + * - everything else → JSON.stringify (truncated) or fallback text + */ +const unknownError = 'Unknown error'; + +export function extractErrorMessage(error: unknown): string { + if (error instanceof Error) return error.message || error.name || unknownError; + if (typeof error === 'string') return error; + if (typeof error !== 'object' || error === null) return unknownError; + + const obj = error as Record; + + const direct = getStringField(obj, 'message') || getStringField(obj, 'error'); + if (direct) return direct; + + const nested = getNestedErrorMessage(obj); + if (nested) return nested; + + const body = getResponseBodyMessage(obj); + if (body) return body; + + try { + return JSON.stringify(error).slice(0, 500); + } catch { + return unknownError; + } +} + +function getStringField(obj: Record, field: string): string | null { + const value = obj[field]; + return typeof value === 'string' && value ? value : null; +} + +function getNestedErrorMessage(obj: Record): string | null { + const nested = obj.error; + if (typeof nested === 'object' && nested !== null) { + return getStringField(nested as Record, 'message'); + } + return null; +} + +function getResponseBodyMessage(obj: Record): string | null { + if (typeof obj.responseBody !== 'string') return null; + try { + const body = JSON.parse(obj.responseBody); + return body.error?.message || null; + } catch { + return null; + } +} diff --git a/packages/core/src/errors/index.ts b/packages/core/src/errors/index.ts index 1c31043d5..677bf2d80 100644 --- a/packages/core/src/errors/index.ts +++ b/packages/core/src/errors/index.ts @@ -1,2 +1,3 @@ +export * from './extract-error-message'; export * from './http'; export * from './types'; diff --git a/packages/openapi/src/admin/setting/ai-key-stats.ts b/packages/openapi/src/admin/setting/ai-key-stats.ts new file mode 100644 index 000000000..c8814918f --- /dev/null +++ b/packages/openapi/src/admin/setting/ai-key-stats.ts @@ -0,0 +1,53 @@ +import type { RouteConfig } from '@asteasolutions/zod-to-openapi'; +import { z } from 'zod'; +import { axios } from '../../axios'; +import { registerRoute } from '../../utils'; + +export const aiKeyStatsVoSchema = z.object({ + groups: z.record( + z.string(), + z.object({ + keys: z.array( + z.object({ + index: z.number(), + fingerprint: z.string(), + totalRequests: z.number(), + totalFailures: z.number(), + activeRequests: z.number(), + lastUsedAt: z.number().nullable(), + isActive: z.boolean(), + lastError: z.string().nullable(), + }) + ), + totalSlots: z.number(), + activeSlots: z.number(), + waitingCount: z.number(), + }) + ), +}); + +export type IAiKeyStatsVo = z.infer; + +export const AI_KEY_STATS = '/admin/setting/ai-key-stats'; + +export const AiKeyStatsRoute: RouteConfig = registerRoute({ + method: 'get', + path: AI_KEY_STATS, + description: 'Get per-key usage statistics for AI Gateway API keys', + responses: { + 200: { + description: 'Key statistics by group', + content: { + 'application/json': { + schema: aiKeyStatsVoSchema, + }, + }, + }, + }, + tags: ['admin', 'setting'], +}); + +export const getAiKeyStats = async (): Promise => { + const response = await axios.get(AI_KEY_STATS); + return response.data; +}; diff --git a/packages/openapi/src/admin/setting/index.ts b/packages/openapi/src/admin/setting/index.ts index cc4d68dbd..437970c4e 100644 --- a/packages/openapi/src/admin/setting/index.ts +++ b/packages/openapi/src/admin/setting/index.ts @@ -8,3 +8,4 @@ export * from './batch-test-llm'; export * from './test-api-key'; export * from './test-public-access'; export * from './set-transport-config'; +export * from './ai-key-stats'; diff --git a/packages/openapi/src/admin/setting/update.ts b/packages/openapi/src/admin/setting/update.ts index 42f6d165d..ae82425d5 100644 --- a/packages/openapi/src/admin/setting/update.ts +++ b/packages/openapi/src/admin/setting/update.ts @@ -435,6 +435,43 @@ export const AttachmentTransferModeValues = ['url', 'base64'] as const; export type AttachmentTransferMode = (typeof AttachmentTransferModeValues)[number]; export const attachmentTransferModeSchema = z.enum(AttachmentTransferModeValues); +// Task types for AI concurrency group routing +export const TaskTypeValues = ['text', 'image'] as const; +export type TaskType = (typeof TaskTypeValues)[number]; +export const taskTypeSchema = z.enum(TaskTypeValues); + +// API key entry within a concurrency group (with verification status) +export const concurrencyKeyEntrySchema = z.object({ + apiKey: z.string(), + status: z.enum(['verified', 'untested', 'error']).default('untested'), +}); + +export type IConcurrencyKeyEntry = z.infer; + +// Named group of API keys sharing a concurrency pool, scoped to specific task types +export const concurrencyGroupSchema = z.object({ + id: z.string(), + name: z.string(), + taskTypes: z.array(taskTypeSchema).default([]), + keys: z.array(concurrencyKeyEntrySchema).default([]), + perKey: z.number().min(1).max(100).default(5).optional(), +}); + +export type IConcurrencyGroup = z.infer; + +// Vertex BYOK credential for free quota optimization via AI Gateway BYOK +// @see https://vercel.com/docs/ai-gateway/authentication-and-byok/byok#credential-structure-by-provider +export const vertexByokCredentialSchema = z.object({ + project: z.string(), + location: z.string(), + googleCredentials: z.object({ + privateKey: z.string(), + clientEmail: z.string(), + }), +}); + +export type IVertexByokCredential = z.infer; + export const aiConfigSchema = z.object({ llmProviders: z.array(llmProviderSchema).default([]), embeddingModel: z.string().optional(), @@ -455,6 +492,14 @@ export const aiConfigSchema = z.object({ attachmentTest: attachmentTestSchema.optional(), // Attachment transfer mode: 'url' (default) or 'base64' attachmentTransferMode: attachmentTransferModeSchema.default('url').optional(), + // Multiple AI Gateway API keys for concurrency scaling via key rotation + aiGatewayApiKeys: z.array(z.string()).optional(), + // Vertex AI BYOK credential (free quota optimization for Google models) + vertexByokCredential: vertexByokCredentialSchema.optional(), + // Named concurrency groups: each group owns a set of API keys and task types + concurrencyGroups: z.array(concurrencyGroupSchema).optional(), + // Default concurrency slots per API key (applies when groups don't specify perKey) + concurrencyPerKey: z.number().min(1).max(100).optional(), }); export type IAIConfig = z.infer; @@ -493,6 +538,8 @@ export const v2FeatureSchema = z.enum([ 'paste', 'clear', 'importRecords', + 'createField', + 'duplicateField', 'updateField', 'convertField', ]); diff --git a/packages/v2/adapter-repository-postgres/src/repositories/PostgresTableRepository.spec.ts b/packages/v2/adapter-repository-postgres/src/repositories/PostgresTableRepository.spec.ts index 905751bb9..955183741 100644 --- a/packages/v2/adapter-repository-postgres/src/repositories/PostgresTableRepository.spec.ts +++ b/packages/v2/adapter-repository-postgres/src/repositories/PostgresTableRepository.spec.ts @@ -826,6 +826,77 @@ describe('PostgresTableRepository (pg)', () => { } }); + it('persists and rehydrates aiConfig on create', async () => { + const c = container.createChildContainer(); + const db = await createPgDb(pgContainer.getConnectionUri()); + await registerV2PostgresStateAdapter(c, { + db, + ensureSchema: true, + }); + const repo = c.resolve(v2CoreTokens.tableRepository); + + try { + const baseId = BaseId.create(`bse${'g'.repeat(16)}`)._unsafeUnwrap(); + const actorId = ActorId.create('system')._unsafeUnwrap(); + const context = { actorId }; + const spaceId = `spc${getRandomString(16)}`; + + await db + .insertInto('space') + .values({ id: spaceId, name: 'AI Space', created_by: actorId.toString() }) + .execute(); + await db + .insertInto('base') + .values({ + id: baseId.toString(), + space_id: spaceId, + name: 'AI Base', + order: 1, + created_by: actorId.toString(), + }) + .execute(); + + const tableName = TableName.create('AI Table')._unsafeUnwrap(); + const titleName = FieldName.create('Title')._unsafeUnwrap(); + const aiName = FieldName.create('AI Summary')._unsafeUnwrap(); + + const builder = Table.builder().withBaseId(baseId).withName(tableName); + builder.field().singleLineText().withName(titleName).primary().done(); + builder.field().singleLineText().withName(aiName).done(); + builder.view().defaultGrid().done(); + + const table = builder.build()._unsafeUnwrap(); + const aiField = table.getFields().find((field) => field.name().equals(aiName)); + expect(aiField).toBeDefined(); + if (!aiField) return; + + const aiConfig = { + type: 'summary', + modelKey: 'openai@gpt-4o@gpt', + sourceFieldId: table.primaryFieldId().toString(), + }; + aiField.setAiConfig(aiConfig)._unsafeUnwrap(); + + (await repo.insert(context, table))._unsafeUnwrap(); + + const row = await db + .selectFrom('field') + .select(['id', 'ai_config']) + .where('id', '=', aiField.id().toString()) + .where('deleted_time', 'is', null) + .executeTakeFirst(); + expect(row).toBeDefined(); + expect(JSON.parse(row?.ai_config ?? 'null')).toEqual(aiConfig); + + const spec = Table.specs(baseId).byId(table.id()).build()._unsafeUnwrap(); + const loaded = (await repo.findOne(context, spec))._unsafeUnwrap(); + const loadedAiField = loaded.getFields().find((field) => field.id().equals(aiField.id())); + expect(loadedAiField?.aiConfig()).toEqual(aiConfig); + } finally { + await db.destroy(); + } + }); + it('rejects duplicate db table names within a base', async () => { const c = container.createChildContainer(); const db = await createPgDb(pgContainer.getConnectionUri()); diff --git a/packages/v2/adapter-repository-postgres/src/repositories/PostgresTableRepository.ts b/packages/v2/adapter-repository-postgres/src/repositories/PostgresTableRepository.ts index 3a5ecdfb1..fffdd275d 100644 --- a/packages/v2/adapter-repository-postgres/src/repositories/PostgresTableRepository.ts +++ b/packages/v2/adapter-repository-postgres/src/repositories/PostgresTableRepository.ts @@ -545,6 +545,7 @@ export class PostgresTableRepository implements core.ITableRepository { 'type', 'options', 'meta', + 'ai_config', 'cell_value_type', 'is_multiple_cell_value', 'not_null', @@ -640,6 +641,7 @@ export class PostgresTableRepository implements core.ITableRepository { 'type', 'options', 'meta', + 'ai_config', 'cell_value_type', 'is_multiple_cell_value', 'not_null', @@ -908,6 +910,7 @@ export class PostgresTableRepository implements core.ITableRepository { type: string; options: string | null; meta: string | null; + ai_config: string | null; cell_value_type: string | null; is_multiple_cell_value: boolean | null; not_null: boolean | null; @@ -972,6 +975,7 @@ export class PostgresTableRepository implements core.ITableRepository { type: string; options: string | null; meta: string | null; + ai_config: string | null; cell_value_type: string | null; is_multiple_cell_value: boolean | null; not_null: boolean | null; @@ -1060,10 +1064,12 @@ export class PostgresTableRepository implements core.ITableRepository { const lookupOptions = resolveLookupOptions(); const dbFieldName = row.db_field_name ?? undefined; const dbFieldType = row.db_field_type ?? undefined; + const aiConfig = this.parseJsonValue(row.ai_config); const baseCommon = { id: row.id, name: row.name, ...(row.description !== null ? { description: row.description } : { description: null }), + ...(row.ai_config !== null ? { aiConfig } : {}), dbFieldName, dbFieldType, ...(row.not_null ? { notNull: true } : {}), @@ -1612,16 +1618,36 @@ export class PostgresTableRepository implements core.ITableRepository { defaultValue?: string | ReadonlyArray; preventAutoNewOptions?: boolean; } { + const normalizeColor = (color: unknown, index: number): string => { + if (typeof color === 'string' && core.fieldColorValues.includes(color as never)) { + return color; + } + return core.fieldColorValues[index % core.fieldColorValues.length]; + }; + if (Array.isArray(raw.options)) { const choices = raw.options.map((name, index) => ({ id: `cho${core.getRandomString(8)}`, name: String(name), - color: core.fieldColorValues[index % core.fieldColorValues.length], + color: normalizeColor(undefined, index), })); return { choices }; } - const choices = Array.isArray(raw.choices) ? raw.choices : []; + const choices = Array.isArray(raw.choices) + ? raw.choices.map((choice, index) => { + const item = + choice && typeof choice === 'object' ? (choice as Record) : {}; + return { + id: + typeof item.id === 'string' && item.id.length > 0 + ? item.id + : `cho${core.getRandomString(8)}`, + name: typeof item.name === 'string' ? item.name : String(item.name ?? ''), + color: normalizeColor(item.color, index), + }; + }) + : []; const defaultValue = raw.defaultValue; const preventAutoNewOptions = typeof raw.preventAutoNewOptions === 'boolean' ? raw.preventAutoNewOptions : undefined; diff --git a/packages/v2/adapter-repository-postgres/src/repositories/TableFieldPersistenceBuilder.ts b/packages/v2/adapter-repository-postgres/src/repositories/TableFieldPersistenceBuilder.ts index 6943623c1..882b95cb5 100644 --- a/packages/v2/adapter-repository-postgres/src/repositories/TableFieldPersistenceBuilder.ts +++ b/packages/v2/adapter-repository-postgres/src/repositories/TableFieldPersistenceBuilder.ts @@ -30,7 +30,7 @@ export type TableFieldRow = { description: string | null; options: string | null; meta: string | null; - ai_config: null; + ai_config: string | null; type: string; cell_value_type: string; is_multiple_cell_value: boolean; @@ -255,13 +255,18 @@ export class TableFieldPersistenceBuilder { : null; const persistedType = this.resolvePersistedFieldType(params.fieldDto); + const serializedAiConfig = + params.fieldDto.aiConfig === undefined || params.fieldDto.aiConfig === null + ? null + : JSON.stringify(params.fieldDto.aiConfig); + return { id: params.fieldDto.id, name: params.fieldDto.name, description: params.fieldDto.description ?? null, options: this.serializeFieldOptions(params.fieldDto), meta: this.serializeFieldMeta(params.fieldDto), - ai_config: null, + ai_config: serializedAiConfig, type: persistedType, cell_value_type: params.storageType.cellValueType, is_multiple_cell_value: params.storageType.isMultipleCellValue, @@ -334,8 +339,9 @@ export class TableFieldPersistenceBuilder { if (field.isLookup && field.lookupOptions) { const linkOptions = this.resolveLinkFieldOptions(field.lookupOptions.linkFieldId); if (!linkOptions) return JSON.stringify(field.lookupOptions); + const normalizedLinkOptions = this.normalizeLookupLinkedOptions(linkOptions); return JSON.stringify({ - ...linkOptions, + ...normalizedLinkOptions, ...field.lookupOptions, linkFieldId: field.lookupOptions.linkFieldId, }); @@ -346,7 +352,7 @@ export class TableFieldPersistenceBuilder { const linkOptions = this.resolveLinkFieldOptions(field.config.linkFieldId); if (!linkOptions) return JSON.stringify(field.config); return JSON.stringify({ - ...linkOptions, + ...this.normalizeLookupLinkedOptions(linkOptions), ...field.config, linkFieldId: field.config.linkFieldId, }); @@ -373,6 +379,19 @@ export class TableFieldPersistenceBuilder { return null; } + private normalizeLookupLinkedOptions( + linkOptions: ILinkFieldOptionsDTO + ): Partial { + const options: Partial = { ...linkOptions }; + if (options.isOneWay === false) { + delete options.isOneWay; + } + if ('symmetricFieldId' in options) { + delete options.symmetricFieldId; + } + return options; + } + private resolveLinkFieldOptions( linkFieldId: string | undefined ): ILinkFieldOptionsDTO | undefined { diff --git a/packages/v2/adapter-repository-postgres/src/repositories/visitors/TableRecordConditionWhereVisitor.spec.ts b/packages/v2/adapter-repository-postgres/src/repositories/visitors/TableRecordConditionWhereVisitor.spec.ts index b6caacfe4..6b2095bbe 100644 --- a/packages/v2/adapter-repository-postgres/src/repositories/visitors/TableRecordConditionWhereVisitor.spec.ts +++ b/packages/v2/adapter-repository-postgres/src/repositories/visitors/TableRecordConditionWhereVisitor.spec.ts @@ -10,6 +10,7 @@ import { ok, RecordByIdsSpec, RecordConditionDateValue, + RecordConditionFieldReferenceValue, RecordConditionLiteralListValue, RecordConditionLiteralValue, RecordId, @@ -542,4 +543,21 @@ describe('TableRecordConditionWhereVisitor', () => { expect(compiled.sql).toContain('__id'); expect(compiled.parameters).toEqual(recordIds.map((id) => id.toString())); }); + + test('supports date comparison with field reference values', () => { + const field = fixture.fields.date; + const value = RecordConditionFieldReferenceValue.create(field)._unsafeUnwrap(); + const spec = field.spec().create({ operator: 'isBefore', value }); + expect(spec.isOk()).toBe(true); + if (spec.isErr()) return; + + const visitor = new TableRecordConditionWhereVisitor({ tableAlias: 't' }); + const visitResult = spec.value.accept(visitor); + expect(visitResult.isOk()).toBe(true); + const where = visitor.where()._unsafeUnwrap(); + const compiled = compileCondition(db, where); + + expect(compiled.sql).toContain('"t"."col_due_date" < "t"."col_due_date"'); + expect(compiled.parameters).toEqual([]); + }); }); diff --git a/packages/v2/adapter-repository-postgres/src/repositories/visitors/TableRecordConditionWhereVisitor.ts b/packages/v2/adapter-repository-postgres/src/repositories/visitors/TableRecordConditionWhereVisitor.ts index 28b36ba04..b7c897250 100644 --- a/packages/v2/adapter-repository-postgres/src/repositories/visitors/TableRecordConditionWhereVisitor.ts +++ b/packages/v2/adapter-repository-postgres/src/repositories/visitors/TableRecordConditionWhereVisitor.ts @@ -498,9 +498,19 @@ const buildDateComparisonCondition = ( if (!value) return err(core.domainError.unexpected({ message: 'Record condition requires value' })); const column = yield* resolveColumn(field, tableAlias); + const columnRef = sql.ref(column); + + if (core.isRecordConditionFieldReferenceValue(value)) { + const rightColumn = yield* resolveColumn(value.field(), tableAlias); + const right = sql.ref(rightColumn); + if (operator === '>') return ok(sql`${columnRef} > ${right}`); + if (operator === '>=') return ok(sql`${columnRef} >= ${right}`); + if (operator === '<') return ok(sql`${columnRef} < ${right}`); + return ok(sql`${columnRef} <= ${right}`); + } + const dateValue = yield* resolveDateValue(value); const range = yield* resolveDateRange(dateValue, resolveDateFormatting(field)); - const columnRef = sql.ref(column); const boundary = operator === '>' || operator === '<=' ? range.end : range.start; const right = sql`${boundary}`; if (operator === '>') return ok(sql`${columnRef} > ${right}`); diff --git a/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedFieldBackfillService.ts b/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedFieldBackfillService.ts index 710330f11..a9b7850c2 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedFieldBackfillService.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedFieldBackfillService.ts @@ -294,6 +294,7 @@ export class ComputedFieldBackfillService { // This will select all records in the table const builder = new ComputedTableRecordQueryBuilder(db, { typeValidationStrategy: this.typeValidationStrategy, + forceLookupArrayOutput: true, }) .from(input.table) .select([fieldId]); @@ -387,6 +388,7 @@ export class ComputedFieldBackfillService { // Build SELECT query for all computed fields const builder = new ComputedTableRecordQueryBuilder(db, { typeValidationStrategy: this.typeValidationStrategy, + forceLookupArrayOutput: true, }) .from(input.table) .select(fieldIds); diff --git a/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedFieldUpdater.ts b/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedFieldUpdater.ts index e870f5e55..37b73bef0 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedFieldUpdater.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedFieldUpdater.ts @@ -832,6 +832,7 @@ export class ComputedFieldUpdater { if (!selectQuery) { const builder = new ComputedTableRecordQueryBuilder(db, { typeValidationStrategy: this.typeValidationStrategy, + forceLookupArrayOutput: true, }) .from(table) .select(fieldIds) diff --git a/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedUpdatePlanner.ts b/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedUpdatePlanner.ts index 29abc8428..64a59e992 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedUpdatePlanner.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/computed/ComputedUpdatePlanner.ts @@ -595,7 +595,8 @@ export class ComputedUpdatePlanner { }); const cycleFieldIds = findCycleParticipantFieldIds(relevantEdges, computedFieldIds); - const skippedFieldIdSet = cycleFieldIds.size > 0 ? cycleFieldIds : new Set(unsortedFieldIds); + const skippedFieldIdSet = + cycleFieldIds.size > 0 ? cycleFieldIds : new Set(unsortedFieldIds); const skippedFieldIds = [...skippedFieldIdSet]; const message = `Computed field dependency cycle detected. Total unsorted: ${unsortedFieldIds.length}. Skipped cycle fields: ${skippedFieldIds.length}. Cycle: [${cycleInfoText}]. Sample fields: [${sampleFields.join(', ')}]`; const allowSkip = context.cyclePolicy === 'skip'; @@ -607,7 +608,9 @@ export class ComputedUpdatePlanner { ); } - computedFieldIds = new Set([...computedFieldIds].filter((id) => !skippedFieldIdSet.has(id))); + computedFieldIds = new Set( + [...computedFieldIds].filter((id) => !skippedFieldIdSet.has(id)) + ); relevantEdges = relevantEdges.filter( (edge) => computedFieldIds.has(edge.fromFieldId.toString()) && diff --git a/packages/v2/adapter-table-repository-postgres/src/record/computed/UpdateFromSelectBuilder.ts b/packages/v2/adapter-table-repository-postgres/src/record/computed/UpdateFromSelectBuilder.ts index e948901c1..4cc03fc33 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/computed/UpdateFromSelectBuilder.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/computed/UpdateFromSelectBuilder.ts @@ -1,12 +1,12 @@ import { domainError, Field, FieldType, FieldValueTypeVisitor } from '@teable/v2-core'; import type { DomainError, + ConditionalLookupField, FieldId, + LookupField, Table, TableId, - ConditionalLookupField, FieldValueType, - LookupField, } from '@teable/v2-core'; import type { CompiledQuery, @@ -275,6 +275,7 @@ type FieldMapping = { fieldId: FieldId; isLookup: boolean; isLookupMultiValue: boolean; + isLookupAutoNumber: boolean; dbFieldType: string; }; @@ -285,19 +286,6 @@ const fieldIsJson = (field: Field): boolean => { return jsonSpecResult.value.isSatisfiedBy(field); }; -const shouldSkipLookupAutoNumberUpdate = (field: Field): boolean => { - if ( - !field.type().equals(FieldType.lookup()) && - !field.type().equals(FieldType.conditionalLookup()) - ) { - return false; - } - const lookupField = field as LookupField | ConditionalLookupField; - const innerTypeResult = lookupField.innerFieldType(); - if (innerTypeResult.isErr()) return false; - return innerTypeResult.value.equals(FieldType.autoNumber()); -}; - const resolveDbFieldType = ( field: Field, cellValueType: string, @@ -427,12 +415,13 @@ const buildLookupScalarCast = (expression: ReturnType, columnType: s const buildLookupAssignmentFromRef = ( sourceRef: unknown, lookupDbFieldType: string, - isLookupMultiValue: boolean + isLookupMultiValue: boolean, + isLookupAutoNumber: boolean ) => { const normalizedType = normalizeDbFieldType(lookupDbFieldType); if (normalizedType === 'jsonb') { const refJson = sql`to_jsonb(${sourceRef})`; - if (isLookupMultiValue) { + if (isLookupMultiValue && !isLookupAutoNumber) { return refJson; } return sql`(CASE WHEN jsonb_typeof(${refJson}) = 'array' THEN ${refJson} -> 0 ELSE ${refJson} END)`; @@ -455,9 +444,6 @@ const buildFieldMappings = ( if (field.hasError().isError()) { continue; } - if (shouldSkipLookupAutoNumberUpdate(field)) { - continue; - } const dbFieldName = yield* field.dbFieldName(); const columnName = yield* dbFieldName.value(); // Determine if this is a lookup field @@ -467,6 +453,21 @@ const buildFieldMappings = ( const isLookup = field.type().equals(FieldType.lookup()) || field.type().equals(FieldType.conditionalLookup()); + const isLookupAutoNumber = (() => { + if (field.type().equals(FieldType.lookup())) { + return (field as LookupField) + .innerFieldType() + .map((innerType) => innerType.equals(FieldType.autoNumber())) + .unwrapOr(false); + } + if (field.type().equals(FieldType.conditionalLookup())) { + return (field as ConditionalLookupField) + .innerFieldType() + .map((innerType) => innerType.equals(FieldType.autoNumber())) + .unwrapOr(false); + } + return false; + })(); const valueType = yield* field.accept(valueTypeVisitor); const isLookupMultiValue = isLookup && valueType.isMultipleCellValue.toBoolean(); @@ -498,6 +499,13 @@ const buildFieldMappings = ( dbFieldType = 'TEXT'; } + // For multi-value lookups, always use JSON storage semantics. This protects against + // stale scalar dbFieldType metadata that can otherwise produce jsonb=integer DISTINCT + // comparisons during computed updates. + if (isLookup && valueType.isMultipleCellValue.toBoolean()) { + dbFieldType = 'JSON'; + } + // For single-value lookups, resolve the scalar dbFieldType for proper SQL generation. // The SELECT query (built by ComputedTableRecordQueryBuilder) returns JSONB arrays for all // lookup fields. For single-value lookups stored in scalar columns, we need to extract the @@ -516,6 +524,7 @@ const buildFieldMappings = ( fieldId, isLookup, isLookupMultiValue, + isLookupAutoNumber, dbFieldType, }); } @@ -582,7 +591,8 @@ class UpdateAssignmentPlan { return buildLookupAssignmentFromRef( sourceRef, this.mapping.dbFieldType, - this.mapping.isLookupMultiValue + this.mapping.isLookupMultiValue, + this.mapping.isLookupAutoNumber ); case 'json': return sql`to_jsonb(${sourceRef})`; diff --git a/packages/v2/adapter-table-repository-postgres/src/record/query-builder/TableRecordQueryBuilderManager.ts b/packages/v2/adapter-table-repository-postgres/src/record/query-builder/TableRecordQueryBuilderManager.ts index a8fa72d95..b81b47d37 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/query-builder/TableRecordQueryBuilderManager.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/query-builder/TableRecordQueryBuilderManager.ts @@ -74,7 +74,7 @@ export class TableRecordQueryBuilderManager { : new ComputedTableRecordQueryBuilder(db, { typeValidationStrategy: this.typeValidationStrategy, preferStoredLastModifiedFormula: true, - forceLookupArrayOutput: false, + forceLookupArrayOutput: true, }).from(table); const prepareSpan = context.tracer?.startSpan('teable.queryBuilder.prepare'); diff --git a/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedFieldSelectExpressionVisitor.ts b/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedFieldSelectExpressionVisitor.ts index 1e7cad326..648ee0f34 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedFieldSelectExpressionVisitor.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedFieldSelectExpressionVisitor.ts @@ -487,10 +487,11 @@ export class ComputedFieldSelectExpressionVisitor } const orderByResult = this.getLinkOrderBy(linkField); if (orderByResult.isErr()) return err(orderByResult.error); - const isMultiValueResult = field + const lookupIsMultipleResult = field .isMultipleCellValue() .map((multiplicity) => multiplicity.isMultiple()); - if (isMultiValueResult.isErr()) return err(isMultiValueResult.error); + if (lookupIsMultipleResult.isErr()) return err(lookupIsMultipleResult.error); + const isMultiValue = lookupIsMultipleResult.value; const condition = field.lookupOptions().condition(); const lateralAlias = this.lateral.addColumn( field.linkFieldId(), @@ -499,7 +500,7 @@ export class ComputedFieldSelectExpressionVisitor { type: 'lookup', foreignFieldId: field.lookupFieldId(), - isMultiValue: this.forceLookupArrayOutput ? true : isMultiValueResult.value, + isMultiValue: this.forceLookupArrayOutput ? true : isMultiValue, orderBy: orderByResult.value, condition, } diff --git a/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedTableRecordQueryBuilder.spec.ts b/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedTableRecordQueryBuilder.spec.ts index c3a42bb96..4165d5d5c 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedTableRecordQueryBuilder.spec.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedTableRecordQueryBuilder.spec.ts @@ -5,6 +5,7 @@ import { NumberFormatting, NumberFormattingType, TimeFormatting, + createDateField, createSingleLineTextField, DbFieldName, FieldId, @@ -1671,7 +1672,7 @@ describe('ComputedTableRecordQueryBuilder', () => { ); expect(sql).toMatchInlineSnapshot( - `"select "t"."__id" as "__id", "t"."__version" as "__version", "t"."col_category_ref" as "col_category_ref", "cond_fldcccccccccccccccc"."col_conditional_rollup" as "col_conditional_rollup" from "bseaaaaaaaaaaaaaaaa"."tblmmmmmmmmmmmmmmmm" as "t" inner join lateral (select CAST(COALESCE(SUM("f"."col_number"), 0) AS DOUBLE PRECISION) as "col_conditional_rollup" from "bseaaaaaaaaaaaaaaaa"."tblffffffffffffffff" as "f" where "f"."col_category" = $1) as "cond_fldcccccccccccccccc" on true"` + `"select "t"."__id" as "__id", "t"."__version" as "__version", "t"."col_category_ref" as "col_category_ref", "cond_fldcccccccccccccccc"."col_conditional_rollup" as "col_conditional_rollup" from "bseaaaaaaaaaaaaaaaa"."tblmmmmmmmmmmmmmmmm" as "t" inner join lateral (select CAST(COALESCE(SUM("cond_fldcccccccccccccccc_src"."col_number"), 0) AS DOUBLE PRECISION) as "col_conditional_rollup" from (select * from "bseaaaaaaaaaaaaaaaa"."tblffffffffffffffff" as "f" where "f"."col_category" = $1 order by "f"."__auto_number" asc limit $2) as "cond_fldcccccccccccccccc_src") as "cond_fldcccccccccccccccc" on true"` ); }); @@ -1700,7 +1701,7 @@ describe('ComputedTableRecordQueryBuilder', () => { ); expect(sql).toMatchInlineSnapshot( - `"select "t"."__id" as "__id", "t"."__version" as "__version", "t"."col_category_ref" as "col_category_ref", "cond_fldcccccccccccccccc"."col_conditional_rollup" as "col_conditional_rollup" from "bseaaaaaaaaaaaaaaaa"."tblmmmmmmmmmmmmmmmm" as "t" inner join lateral (select CAST(COALESCE(SUM("f"."col_number"), 0) AS DOUBLE PRECISION) as "col_conditional_rollup" from "bseaaaaaaaaaaaaaaaa"."tblffffffffffffffff" as "f" where "f"."col_category" = "t"."col_category_ref") as "cond_fldcccccccccccccccc" on true"` + `"select "t"."__id" as "__id", "t"."__version" as "__version", "t"."col_category_ref" as "col_category_ref", "cond_fldcccccccccccccccc"."col_conditional_rollup" as "col_conditional_rollup" from "bseaaaaaaaaaaaaaaaa"."tblmmmmmmmmmmmmmmmm" as "t" inner join lateral (select CAST(COALESCE(SUM("cond_fldcccccccccccccccc_src"."col_number"), 0) AS DOUBLE PRECISION) as "col_conditional_rollup" from (select * from "bseaaaaaaaaaaaaaaaa"."tblffffffffffffffff" as "f" where "f"."col_category" = "t"."col_category_ref" order by "f"."__auto_number" asc limit $1) as "cond_fldcccccccccccccccc_src") as "cond_fldcccccccccccccccc" on true"` ); }); }); @@ -2087,6 +2088,84 @@ describe('ComputedTableRecordQueryBuilder', () => { } ); + test('uses UTC ISO datetime strings for multi-value lookup aggregation', () => { + const baseId = BaseId.create(BASE_ID)._unsafeUnwrap(); + const tableId = TableId.create(MAIN_TABLE_ID)._unsafeUnwrap(); + const linkFieldId = FieldId.create(LINK_FIELD_ID)._unsafeUnwrap(); + const lookupTargetFieldId = FieldId.create(LOOKUP_TARGET_FIELD_ID)._unsafeUnwrap(); + + const linkConfig = LinkFieldConfig.create({ + relationship: 'oneMany', + foreignTableId: tableId.toString(), + lookupFieldId: lookupTargetFieldId.toString(), + symmetricFieldId: SYMMETRIC_FIELD_ID, + })._unsafeUnwrap(); + + const lookupOptions = LookupOptions.create({ + linkFieldId: linkFieldId.toString(), + foreignTableId: tableId.toString(), + lookupFieldId: lookupTargetFieldId.toString(), + })._unsafeUnwrap(); + + const innerField = createDateField({ + id: FieldId.create(`fld${'i'.repeat(16)}`)._unsafeUnwrap(), + name: FieldName.create('InnerDate')._unsafeUnwrap(), + })._unsafeUnwrap(); + + const builder = Table.builder() + .withId(tableId) + .withBaseId(baseId) + .withName(TableName.create('SelfDateLookup')._unsafeUnwrap()); + builder + .field() + .date() + .withId(lookupTargetFieldId) + .withName(FieldName.create('Due')._unsafeUnwrap()) + .done(); + builder + .field() + .link() + .withId(linkFieldId) + .withName(FieldName.create('Reports')._unsafeUnwrap()) + .withConfig(linkConfig) + .done(); + builder + .field() + .lookup() + .withName(FieldName.create('ReportDueDates')._unsafeUnwrap()) + .withLookupOptions(lookupOptions) + .withInnerField(innerField) + .done(); + builder.view().defaultGrid().done(); + + const table = builder.build({ includeSelf: true })._unsafeUnwrap(); + table + .getFields()[0] + .setDbFieldName(DbFieldName.rehydrate('col_due')._unsafeUnwrap()) + ._unsafeUnwrap(); + table + .getFields()[1] + .setDbFieldName(DbFieldName.rehydrate('col_link_reports')._unsafeUnwrap()) + ._unsafeUnwrap(); + table + .getFields()[2] + .setDbFieldName(DbFieldName.rehydrate('col_lookup_due')._unsafeUnwrap()) + ._unsafeUnwrap(); + + const db = createTestDb(); + const foreignTables = new Map([[tableId.toString(), table]]); + const { sql } = compileQuery( + db, + new ComputedTableRecordQueryBuilder(db, { foreignTables, typeValidationStrategy }).from( + table + ) + ); + + expect(sql).toContain( + `jsonb_agg(to_jsonb(to_char("f"."col_due" AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"')) order by` + ); + }); + test.each(relationships)('self-ref %s with lookup and rollup snapshot', (relationship) => { const db = createTestDb(); const { table, tableId } = createSelfRefWithLookupRollup(relationship); diff --git a/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedTableRecordQueryBuilder.ts b/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedTableRecordQueryBuilder.ts index 52c88f1ae..64e8668fd 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedTableRecordQueryBuilder.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/query-builder/computed/ComputedTableRecordQueryBuilder.ts @@ -55,13 +55,27 @@ const T = COMPUTED_TABLE_ALIAS; // main table alias const F = 'f'; // foreign table alias in lateral const DEFAULT_CONDITIONAL_ORDER_BY = { column: '__auto_number', direction: 'asc' } as const; +const parsePositiveInt = (raw: string | undefined, fallback: number): number => { + if (!raw) return fallback; + const parsed = Number(raw); + if (!Number.isFinite(parsed) || parsed <= 0) { + return fallback; + } + return Math.floor(parsed); +}; + +const CONDITIONAL_QUERY_MAX_LIMIT = parsePositiveInt(process.env.CONDITIONAL_QUERY_MAX_LIMIT, 5000); +const CONDITIONAL_QUERY_DEFAULT_LIMIT = Math.min( + parsePositiveInt(process.env.CONDITIONAL_QUERY_DEFAULT_LIMIT, CONDITIONAL_QUERY_MAX_LIMIT), + CONDITIONAL_QUERY_MAX_LIMIT +); + type ResolvedOrderBy = { column: string; direction: 'asc' | 'desc'; userLikeMode?: 'single' | 'multiple'; userLikeSource?: 'field' | 'system'; }; - /** * Configuration for dirty record filtering. * When provided, the query will INNER JOIN with the dirty table early @@ -594,7 +608,8 @@ export class ComputedTableRecordQueryBuilder implements ITableRecordQueryBuilder const sortClause = condition ? yield* this.resolveConditionalSort(foreignTable, condition) : null; - const limitValue = condition?.limit(); + const configuredLimit = condition?.limit(); + const limitValue = configuredLimit ?? CONDITIONAL_QUERY_DEFAULT_LIMIT; const isConditionalDerived = firstColumnType?.type === 'conditionalLookup' || firstColumnType?.type === 'conditionalRollup'; @@ -987,6 +1002,53 @@ export class ComputedTableRecordQueryBuilder implements ITableRecordQueryBuilder ); } + private buildPerRowNestedJsonTextExpr(colRef: RawBuilder): RawBuilder { + const colJson = sql`to_jsonb(${colRef})`; + const normalized = sql`(CASE + WHEN ${colRef} IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(${colJson}) = 'array' THEN ${colJson} + WHEN jsonb_typeof(${colJson}) = 'null' THEN '[]'::jsonb + ELSE jsonb_build_array(${colJson}) + END)`; + return sql`( + SELECT string_agg( + ${sql.raw(extractJsonScalarText('leaf'))}, + ', ' + ORDER BY outer_ord, inner_ord + ) + FROM jsonb_array_elements(${normalized}) WITH ORDINALITY AS outer_elem(elem, outer_ord) + CROSS JOIN LATERAL jsonb_array_elements( + CASE + WHEN jsonb_typeof(outer_elem.elem) = 'array' THEN outer_elem.elem + ELSE jsonb_build_array(outer_elem.elem) + END + ) WITH ORDINALITY AS inner_elem(leaf, inner_ord) + )`; + } + + private buildDistinctNestedJsonTextArrayExpr( + baseAggregate: RawBuilder + ): RawBuilder { + return sql`( + SELECT jsonb_agg(to_jsonb(v.val)) + FROM ( + SELECT DISTINCT val + FROM ( + SELECT ${sql.raw(extractJsonScalarText('leaf'))} AS val + FROM jsonb_array_elements(COALESCE(${baseAggregate}, '[]'::jsonb)) AS row_elem(elem) + CROSS JOIN LATERAL jsonb_array_elements( + CASE + WHEN jsonb_typeof(row_elem.elem) = 'array' THEN row_elem.elem + ELSE jsonb_build_array(row_elem.elem) + END + ) AS leaf_elem(leaf) + ) AS flattened + WHERE val IS NOT NULL AND val <> '' + ORDER BY val + ) AS v + )`; + } + /** * Build lookup aggregation expression. * @@ -1069,8 +1131,16 @@ export class ComputedTableRecordQueryBuilder implements ITableRecordQueryBuilder ); } - // For regular columns, use to_jsonb() to convert to JSONB - const aggExpr = sql`jsonb_agg(to_jsonb(${colRef})${orderByRef}) FILTER (WHERE ${colRef} IS NOT NULL)`; + const fieldValueTypeResult = foreignField.accept(new FieldValueTypeVisitor()); + const isDateTimeLookupTarget = + fieldValueTypeResult.isOk() && + fieldValueTypeResult.value.cellValueType.equals(CellValueType.dateTime()); + + const lookupValueExpr = + isMultiValue && isDateTimeLookupTarget + ? sql`to_jsonb(to_char(${colRef} AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'))` + : sql`to_jsonb(${colRef})`; + const aggExpr = sql`jsonb_agg(${lookupValueExpr}${orderByRef}) FILTER (WHERE ${colRef} IS NOT NULL)`; return ok( isMultiValue ? aggExpr.as(outputAlias) : sql`${aggExpr} -> 0`.as(outputAlias) ); @@ -1171,6 +1241,10 @@ export class ComputedTableRecordQueryBuilder implements ITableRecordQueryBuilder return ok(sql`(COUNT(CASE WHEN ${colRef}::boolean THEN 1 END) % 2 = 1)`); case 'array_join({values})': case 'concatenate({values})': { + if (foreignField.type().equals(FieldType.link())) { + const rowTextExpr = this.buildPerRowNestedJsonTextExpr(colRef); + return ok(sql`STRING_AGG(${rowTextExpr}, ', '${orderBySql})`); + } const columnName = yield* foreignField .dbFieldName() .andThen((dbFieldName) => dbFieldName.value()); @@ -1189,8 +1263,15 @@ export class ComputedTableRecordQueryBuilder implements ITableRecordQueryBuilder sql`STRING_AGG(${formattedSql ? sql.raw(formattedSql) : sql`${colRef}::text`}, ', '${orderBySql})` ); } - case 'array_unique({values})': + case 'array_unique({values})': { + if (foreignField.type().equals(FieldType.link())) { + const baseAggregate = orderByExpr + ? sql`jsonb_agg(to_jsonb(${colRef}) ORDER BY ${orderByExpr}) FILTER (WHERE ${colRef} IS NOT NULL)` + : sql`jsonb_agg(to_jsonb(${colRef})) FILTER (WHERE ${colRef} IS NOT NULL)`; + return ok(this.buildDistinctNestedJsonTextArrayExpr(baseAggregate)); + } return ok(sql`json_agg(DISTINCT ${colRef})`); + } case 'array_compact({values})': { const baseAggregate = orderByExpr ? sql`jsonb_agg(${colRef} ORDER BY ${orderByExpr}) FILTER (WHERE (${colRef}) IS NOT NULL AND (${colRef})::text <> '')` diff --git a/packages/v2/adapter-table-repository-postgres/src/record/visitors/TableRecordConditionWhereVisitor.spec.ts b/packages/v2/adapter-table-repository-postgres/src/record/visitors/TableRecordConditionWhereVisitor.spec.ts index 1ed6def2a..81eb54144 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/visitors/TableRecordConditionWhereVisitor.spec.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/visitors/TableRecordConditionWhereVisitor.spec.ts @@ -4,6 +4,7 @@ import { CheckboxConditionSpec, DbFieldName, FieldName, + RecordConditionFieldReferenceValue, LongTextConditionSpec, NumberConditionSpec, RecordConditionLiteralListValue, @@ -79,6 +80,8 @@ const createTestTable = () => { builder.field().singleSelect().withName(FieldName.create('Status')._unsafeUnwrap()).done(); builder.field().checkbox().withName(FieldName.create('Done')._unsafeUnwrap()).done(); builder.field().longText().withName(FieldName.create('Notes')._unsafeUnwrap()).done(); + builder.field().date().withName(FieldName.create('Due Date')._unsafeUnwrap()).done(); + builder.field().date().withName(FieldName.create('Cutoff Date')._unsafeUnwrap()).done(); builder.view().defaultGrid().done(); const table = builder.build()._unsafeUnwrap(); @@ -88,6 +91,10 @@ const createTestTable = () => { fields[2].setDbFieldName(DbFieldName.rehydrate('col_status')._unsafeUnwrap())._unsafeUnwrap(); fields[3].setDbFieldName(DbFieldName.rehydrate('col_done')._unsafeUnwrap())._unsafeUnwrap(); fields[4].setDbFieldName(DbFieldName.rehydrate('col_notes')._unsafeUnwrap())._unsafeUnwrap(); + fields[5].setDbFieldName(DbFieldName.rehydrate('col_due_date')._unsafeUnwrap())._unsafeUnwrap(); + fields[6] + .setDbFieldName(DbFieldName.rehydrate('col_cutoff_date')._unsafeUnwrap()) + ._unsafeUnwrap(); return { table, @@ -96,6 +103,8 @@ const createTestTable = () => { statusField: fields[2], doneField: fields[3], notesField: fields[4], + dueDateField: fields[5], + cutoffDateField: fields[6], }; }; @@ -121,7 +130,15 @@ const buildWhereFor = ( describe('TableRecordConditionWhereVisitor NULL handling', () => { const db = createTestDb(); - const { nameField, scoreField, statusField, doneField, notesField } = createTestTable(); + const { + nameField, + scoreField, + statusField, + doneField, + notesField, + dueDateField, + cutoffDateField, + } = createTestTable(); // ---- isNot ---- @@ -251,6 +268,29 @@ describe('TableRecordConditionWhereVisitor NULL handling', () => { }); }); + describe('date field reference comparisons', () => { + test('date isBefore with field reference uses host table alias', () => { + const value = RecordConditionFieldReferenceValue.create(cutoffDateField)._unsafeUnwrap(); + const spec = dueDateField.spec().create({ operator: 'isBefore', value }); + expect(spec.isOk()).toBe(true); + if (spec.isErr()) return; + + const visitor = new TableRecordConditionWhereVisitor({ + tableAlias: 'f', + hostTableAlias: 't', + }); + const visitResult = spec.value.accept(visitor); + expect(visitResult.isOk()).toBe(true); + const where = visitor.where(); + expect(where.isOk()).toBe(true); + if (where.isErr()) return; + + const { sql, parameters } = compileWhere(db, where.value); + expect(sql).toContain('("f"."col_due_date")::date < ("t"."col_cutoff_date")::date'); + expect(parameters).toEqual([]); + }); + }); + // ---- isEmpty / isNotEmpty ---- describe('isEmpty / isNotEmpty operators', () => { diff --git a/packages/v2/adapter-table-repository-postgres/src/record/visitors/TableRecordConditionWhereVisitor.ts b/packages/v2/adapter-table-repository-postgres/src/record/visitors/TableRecordConditionWhereVisitor.ts index 2001eb5a9..5c8def391 100644 --- a/packages/v2/adapter-table-repository-postgres/src/record/visitors/TableRecordConditionWhereVisitor.ts +++ b/packages/v2/adapter-table-repository-postgres/src/record/visitors/TableRecordConditionWhereVisitor.ts @@ -33,6 +33,8 @@ const fieldIsUserOrLink = (field: core.Field): boolean => { return type === 'user' || type === 'createdBy' || type === 'lastModifiedBy' || type === 'link'; }; +const fieldIsLink = (field: core.Field): boolean => field.type().toString() === 'link'; + const buildUserLinkIdArray = ( columnRef: RecordConditionWhere, isMultiple: boolean @@ -46,6 +48,22 @@ const buildJsonbTextArray = (jsonArray: RecordConditionWhere): RecordConditionWh return sql`COALESCE((SELECT array_agg(value) FROM jsonb_array_elements_text(${jsonArray}) AS value), ARRAY[]::text[])`; }; +const buildLinkTitleMatchCondition = ( + columnRef: RecordConditionWhere, + rightColumnRef: RecordConditionWhere +): RecordConditionWhere => { + const normalizedLinks = sql`CASE + WHEN jsonb_typeof(to_jsonb(${columnRef})) = 'array' THEN to_jsonb(${columnRef}) + WHEN to_jsonb(${columnRef}) IS NULL THEN '[]'::jsonb + ELSE jsonb_build_array(to_jsonb(${columnRef})) + END`; + return sql`EXISTS ( + SELECT 1 + FROM jsonb_array_elements(${normalizedLinks}) AS __link + WHERE __link->>'title' = (${rightColumnRef})::text + )`; +}; + /** * Options for TableRecordConditionWhereVisitor. */ @@ -204,6 +222,11 @@ const resolveDateFormatting = (field: core.Field): core.DateTimeFormatting | und return undefined; }; +const shouldCompareAsDateOnly = (field: core.Field): boolean => { + const formatting = resolveDateFormatting(field); + return formatting?.time() === core.TimeFormatting.None; +}; + const resolveDateRange = ( value: core.RecordConditionDateValue, formatting?: core.DateTimeFormatting @@ -463,12 +486,21 @@ const buildIsCondition = ( return ok(sql`jsonb_exists_any(${leftIds}, ${buildJsonbTextArray(rightIds)})`); } + + if (fieldIsLink(field)) { + const rightColumnRef = sql.ref(operand.column); + return ok(buildLinkTitleMatchCondition(columnRef, rightColumnRef)); + } } if (operand.kind === 'field' && core.isRecordConditionFieldReferenceValue(value)) { const referenceField = value.field(); const rightColumnRef = sql.ref(operand.column); + if (shouldCompareAsDateOnly(field) || shouldCompareAsDateOnly(referenceField)) { + return ok(sql`(${columnRef})::date = (${rightColumnRef})::date`); + } + if (fieldIsJson(field) || fieldIsJson(referenceField)) { return ok(sql`to_jsonb(${columnRef}) = to_jsonb(${rightColumnRef})`); } @@ -529,6 +561,10 @@ const buildIsNotCondition = ( const referenceField = value.field(); const rightColumnRef = sql.ref(operand.column); + if (shouldCompareAsDateOnly(field) || shouldCompareAsDateOnly(referenceField)) { + return ok(sql`(${columnRef})::date is distinct from (${rightColumnRef})::date`); + } + if (fieldIsJson(field) || fieldIsJson(referenceField)) { return ok(sql`to_jsonb(${columnRef}) is distinct from to_jsonb(${rightColumnRef})`); } @@ -609,15 +645,35 @@ const buildDateComparisonCondition = ( field: core.Field, value: core.RecordConditionValue | undefined, operator: ComparisonOperator, - tableAlias?: string + tableAlias?: string, + hostTableAlias?: string ): Result => { return safeTry(function* () { if (!value) return err(core.domainError.unexpected({ message: 'Record condition requires value' })); const column = yield* resolveColumn(field, tableAlias); + const columnRef = sql.ref(column); + + if (core.isRecordConditionFieldReferenceValue(value)) { + const rightColumn = yield* resolveColumn(value.field(), hostTableAlias ?? tableAlias); + const right = sql.ref(rightColumn); + const referenceField = value.field(); + const leftExpr: RecordConditionWhere = + shouldCompareAsDateOnly(field) || shouldCompareAsDateOnly(referenceField) + ? sql`(${columnRef})::date` + : columnRef; + const rightExpr: RecordConditionWhere = + shouldCompareAsDateOnly(field) || shouldCompareAsDateOnly(referenceField) + ? sql`(${right})::date` + : right; + if (operator === '>') return ok(sql`${leftExpr} > ${rightExpr}`); + if (operator === '>=') return ok(sql`${leftExpr} >= ${rightExpr}`); + if (operator === '<') return ok(sql`${leftExpr} < ${rightExpr}`); + return ok(sql`${leftExpr} <= ${rightExpr}`); + } + const dateValue = yield* resolveDateValue(value); const range = yield* resolveDateRange(dateValue, resolveDateFormatting(field)); - const columnRef = sql.ref(column); const boundary = operator === '>' || operator === '<=' ? range.end : range.start; const right = sql`${boundary}`; if (operator === '>') return ok(sql`${columnRef} > ${right}`); @@ -1645,7 +1701,7 @@ export class TableRecordConditionWhereVisitor operator: ComparisonOperator ): Result { return this.addConditionResult( - buildDateComparisonCondition(field, value, operator, this.tableAlias) + buildDateComparisonCondition(field, value, operator, this.tableAlias, this.hostTableAlias) ); } diff --git a/packages/v2/adapter-table-repository-postgres/src/schema/visitors/FieldValueChangeCollectorVisitor.ts b/packages/v2/adapter-table-repository-postgres/src/schema/visitors/FieldValueChangeCollectorVisitor.ts index 2b8c95669..869ad8cc0 100644 --- a/packages/v2/adapter-table-repository-postgres/src/schema/visitors/FieldValueChangeCollectorVisitor.ts +++ b/packages/v2/adapter-table-repository-postgres/src/schema/visitors/FieldValueChangeCollectorVisitor.ts @@ -130,7 +130,10 @@ export class FieldValueChangeCollectorVisitor implements ITableSpecVisitor return ok(undefined); } - visitTableDuplicateField(_spec: TableDuplicateFieldSpec): Result { + visitTableDuplicateField(spec: TableDuplicateFieldSpec): Result { + if (spec.newField().computed().toBoolean()) { + this.addSelfBackfill(spec.newField().id()); + } return ok(undefined); } diff --git a/packages/v2/adapter-table-repository-postgres/src/schema/visitors/TableSchemaUpdateVisitor.ts b/packages/v2/adapter-table-repository-postgres/src/schema/visitors/TableSchemaUpdateVisitor.ts index daf92014c..3c1dfe07a 100644 --- a/packages/v2/adapter-table-repository-postgres/src/schema/visitors/TableSchemaUpdateVisitor.ts +++ b/packages/v2/adapter-table-repository-postgres/src/schema/visitors/TableSchemaUpdateVisitor.ts @@ -175,20 +175,27 @@ export class TableSchemaUpdateVisitor return null; } + const valueTypeResult = field.accept(new FieldValueTypeVisitor()); + if (valueTypeResult.isOk()) { + const cellValueType = valueTypeResult.value.cellValueType.toString(); + if (cellValueType === 'boolean' || cellValueType === 'dateTime') { + return null; + } + } + const { db, schema, tableName } = this.params; const fieldId = field.id().toString(); const indexName = TableSchemaUpdateVisitor.getSearchIndexName(tableName, fieldId, dbFieldName); const pgSchema = schema ?? 'public'; - // Build the index expression based on field characteristics. - // This replicates v1 FieldFormatter.getIndexExpression logic. + // Keep search index expressions text-compatible across field storage types + // (e.g. numeric/jsonb), matching v1's text-oriented trigram indexing behavior. const isMultipleResult = field.isMultipleCellValue(); const isMultiple = isMultipleResult.isOk() && isMultipleResult.value.toBoolean(); - let expression: string; - if (isMultiple) { - expression = `"${dbFieldName}"::text`; - } else { - expression = `"${dbFieldName}"`; + let expression = `"${dbFieldName}"::text`; + + if (!isMultiple && fieldType === 'longText') { + expression = `REPLACE(REPLACE(REPLACE("${dbFieldName}"::text, CHR(13), ' '::text), CHR(10), ' '::text), CHR(9), ' '::text)`; } // Wrap in a DO block that only executes if search indexes are enabled for this table @@ -410,10 +417,16 @@ export class TableSchemaUpdateVisitor visitTableAddField( spec: TableAddFieldSpec ): Result, DomainError> { + const visitor = this; const fieldVisitor = PostgresTableSchemaFieldCreateVisitor.forSchemaUpdate(this.params); const addCond = this.addCond.bind(this); return safeTry, DomainError>(function* () { - const statements = yield* spec.field().accept(fieldVisitor); + const statements = [...(yield* spec.field().accept(fieldVisitor))]; + const dbFieldName = yield* visitor.resolveDbFieldNameText(spec.field()); + const createSearchIdx = visitor.createSearchIndexStatement(spec.field(), dbFieldName); + if (createSearchIdx) { + statements.push(createSearchIdx); + } yield* addCond(statements); return ok(statements); }); diff --git a/packages/v2/adapter-table-repository-postgres/src/schema/visitors/__tests__/TableSchemaUpdateVisitor.spec.ts b/packages/v2/adapter-table-repository-postgres/src/schema/visitors/__tests__/TableSchemaUpdateVisitor.spec.ts index 5689c274c..aa22dbda5 100644 --- a/packages/v2/adapter-table-repository-postgres/src/schema/visitors/__tests__/TableSchemaUpdateVisitor.spec.ts +++ b/packages/v2/adapter-table-repository-postgres/src/schema/visitors/__tests__/TableSchemaUpdateVisitor.spec.ts @@ -4,7 +4,17 @@ * These tests validate the SQL statements generated for various * field update operations using Kysely DummyDriver (no actual database connection). */ -import { DbFieldName, FieldId, LinkFieldConfig, UpdateLinkRelationshipSpec } from '@teable/v2-core'; +import { + BaseId, + DbFieldName, + FieldId, + FieldName, + LinkFieldConfig, + Table, + TableAddFieldSpec, + TableName, + UpdateLinkRelationshipSpec, +} from '@teable/v2-core'; import { describe, expect, it } from 'vitest'; import { TableSchemaUpdateVisitor } from '../TableSchemaUpdateVisitor'; @@ -838,10 +848,78 @@ describe('TableSchemaUpdateVisitor', () => { }); describe('visitTableAddField', () => { - it.todo( - 'should delegate to PostgresTableSchemaFieldCreateVisitor' - // Verify: create statements returned - ); + const SCHEMA = 'bseTestBase00000001'; + const TABLE_NAME = 'tblTestTable0000001'; + const TABLE_ID = TABLE_NAME; + const db = createTestDb(); + + const createTable = () => { + const table = Table.builder() + .withBaseId(BaseId.create(SCHEMA)._unsafeUnwrap()) + .withName(TableName.create('Test Table')._unsafeUnwrap()); + table.field().singleLineText().withName(FieldName.create('Name')._unsafeUnwrap()).done(); + table.view().defaultGrid().done(); + return table.build()._unsafeUnwrap(); + }; + + const createVisitor = () => + new TableSchemaUpdateVisitor({ + db, + schema: SCHEMA, + tableName: TABLE_NAME, + tableId: TABLE_ID, + table: createTable(), + }); + + const createField = (params: { id: string; kind: 'singleLineText' | 'checkbox' }) => { + const table = Table.builder() + .withBaseId(BaseId.create(SCHEMA)._unsafeUnwrap()) + .withName(TableName.create('Field Source')._unsafeUnwrap()); + const fieldBuilder = table.field(); + const fieldName = FieldName.create(`Field ${params.id.slice(-4)}`)._unsafeUnwrap(); + const fieldId = FieldId.create(params.id)._unsafeUnwrap(); + + if (params.kind === 'singleLineText') { + fieldBuilder.singleLineText().withId(fieldId).withName(fieldName).done(); + } else { + fieldBuilder.checkbox().withId(fieldId).withName(fieldName).done(); + } + + table.view().defaultGrid().done(); + const fieldSource = table.build()._unsafeUnwrap(); + const field = fieldSource + .getField((candidate) => candidate.id().equals(fieldId)) + ._unsafeUnwrap(); + const dbFieldName = DbFieldName.rehydrate(`fld_${params.id.slice(-8)}`)._unsafeUnwrap(); + field.setDbFieldName(dbFieldName)._unsafeUnwrap(); + return field; + }; + + it('should append search index statement for searchable field types', () => { + const field = createField({ id: 'fldSearchField00001', kind: 'singleLineText' }); + const spec = TableAddFieldSpec.create(field); + const visitor = createVisitor(); + + const result = visitor.visitTableAddField(spec); + expect(result.isOk()).toBe(true); + + const sqls = result._unsafeUnwrap().map((statement) => statement.compile(db).sql); + expect(sqls.some((text) => text.includes("indexname LIKE 'idx_trgm%'"))).toBe(true); + expect(sqls.some((text) => text.includes('CREATE INDEX IF NOT EXISTS'))).toBe(true); + }); + + it('should not append search index statement for unsupported field types', () => { + const field = createField({ id: 'fldCheckboxField001', kind: 'checkbox' }); + const spec = TableAddFieldSpec.create(field); + const visitor = createVisitor(); + + const result = visitor.visitTableAddField(spec); + expect(result.isOk()).toBe(true); + + const sqls = result._unsafeUnwrap().map((statement) => statement.compile(db).sql); + expect(sqls.some((text) => text.includes("indexname LIKE 'idx_trgm%'"))).toBe(false); + expect(sqls.some((text) => text.includes('CREATE INDEX IF NOT EXISTS'))).toBe(false); + }); }); describe('visitTableRemoveField', () => { diff --git a/packages/v2/contract-http-implementation/src/handlers/tables/duplicateField.ts b/packages/v2/contract-http-implementation/src/handlers/tables/duplicateField.ts new file mode 100644 index 000000000..06bb3f277 --- /dev/null +++ b/packages/v2/contract-http-implementation/src/handlers/tables/duplicateField.ts @@ -0,0 +1,52 @@ +import type { IDuplicateFieldEndpointResult } from '@teable/v2-contract-http'; +import { + mapDomainErrorToHttpError, + mapDomainErrorToHttpStatus, + mapDuplicateFieldResultToDto, +} from '@teable/v2-contract-http'; +import { DuplicateFieldCommand } from '@teable/v2-core'; +import type { DuplicateFieldResult, ICommandBus, IExecutionContext } from '@teable/v2-core'; + +export const executeDuplicateFieldEndpoint = async ( + context: IExecutionContext, + rawBody: unknown, + commandBus: ICommandBus +): Promise => { + const commandResult = DuplicateFieldCommand.create(rawBody); + if (commandResult.isErr()) { + const error = commandResult.error; + return { + status: mapDomainErrorToHttpStatus(error), + body: { ok: false, error: mapDomainErrorToHttpError(error) }, + }; + } + + const result = await commandBus.execute( + context, + commandResult.value + ); + if (result.isErr()) { + const error = result.error; + return { + status: mapDomainErrorToHttpStatus(error), + body: { ok: false, error: mapDomainErrorToHttpError(error) }, + }; + } + + const mapped = mapDuplicateFieldResultToDto(result.value); + if (mapped.isErr()) { + const error = mapped.error; + return { + status: mapDomainErrorToHttpStatus(error), + body: { ok: false, error: mapDomainErrorToHttpError(error) }, + }; + } + + return { + status: 200, + body: { + ok: true, + data: mapped.value, + }, + }; +}; diff --git a/packages/v2/contract-http-implementation/src/handlers/tables/index.ts b/packages/v2/contract-http-implementation/src/handlers/tables/index.ts index 0655bdf20..b7df25c64 100644 --- a/packages/v2/contract-http-implementation/src/handlers/tables/index.ts +++ b/packages/v2/contract-http-implementation/src/handlers/tables/index.ts @@ -22,3 +22,4 @@ export * from './updateRecord'; export * from './updateField'; export * from './reorderRecords'; export * from './duplicateRecord'; +export * from './duplicateField'; diff --git a/packages/v2/contract-http-implementation/src/router.ts b/packages/v2/contract-http-implementation/src/router.ts index b0d9f8410..c7393aaff 100644 --- a/packages/v2/contract-http-implementation/src/router.ts +++ b/packages/v2/contract-http-implementation/src/router.ts @@ -40,6 +40,7 @@ import { executeDeleteByRangeEndpoint } from './handlers/tables/deleteByRange'; import { executeRenameTableEndpoint } from './handlers/tables/renameTable'; import { executeUpdateRecordEndpoint } from './handlers/tables/updateRecord'; import { executeReorderRecordsEndpoint } from './handlers/tables/reorderRecords'; +import { executeDuplicateFieldEndpoint } from './handlers/tables/duplicateField'; import { executeDuplicateRecordEndpoint } from './handlers/tables/duplicateRecord'; export interface IV2OrpcRouterOptions { @@ -441,6 +442,34 @@ export const createV2OrpcRouter = (options: IV2OrpcRouterOptions = {}) => { throwDomainError('INTERNAL_SERVER_ERROR', result.body.error); }); + const tablesDuplicateField = os.tables.duplicateField.handler(async ({ input }) => { + const container = await resolveContainer(); + + let executionContext: IExecutionContext; + try { + executionContext = await createExecutionContext(); + } catch { + throw new ORPCError('INTERNAL_SERVER_ERROR', { + message: executionContextErrorMessage, + }); + } + + const commandBus = container.resolve(v2CoreTokens.commandBus); + const result = await executeDuplicateFieldEndpoint(executionContext, input, commandBus); + + if (result.status === 200) return result.body; + + if (result.status === 400) { + throwDomainError('BAD_REQUEST', result.body.error); + } + + if (result.status === 404) { + throwDomainError('NOT_FOUND', result.body.error); + } + + throwDomainError('INTERNAL_SERVER_ERROR', result.body.error); + }); + const tablesPaste = os.tables.paste.handler(async ({ input }) => { const container = await resolveContainer(); @@ -918,6 +947,7 @@ export const createV2OrpcRouter = (options: IV2OrpcRouterOptions = {}) => { createRecords: tablesCreateRecords, updateRecord: tablesUpdateRecord, reorderRecords: tablesReorderRecords, + duplicateField: tablesDuplicateField, duplicateRecord: tablesDuplicateRecord, paste: tablesPaste, clear: tablesClear, diff --git a/packages/v2/contract-http/src/contract.ts b/packages/v2/contract-http/src/contract.ts index 7f30d4a14..6f71747aa 100644 --- a/packages/v2/contract-http/src/contract.ts +++ b/packages/v2/contract-http/src/contract.ts @@ -12,6 +12,7 @@ import { deleteFieldInputSchema, deleteRecordsInputSchema, deleteTableInputSchema, + duplicateFieldInputSchema, duplicateRecordInputSchema, getRecordByIdInputSchema, getTableByIdInputSchema, @@ -40,6 +41,7 @@ import { deleteByRangeOkResponseSchema } from './table/deleteByRange'; import { deleteFieldOkResponseSchema } from './table/deleteField'; import { deleteRecordsOkResponseSchema } from './table/deleteRecords'; import { deleteTableErrorResponseSchema, deleteTableOkResponseSchema } from './table/deleteTable'; +import { duplicateFieldOkResponseSchema } from './table/duplicateField'; import { duplicateRecordOkResponseSchema } from './table/duplicateRecord'; import { explainCreateRecordInputSchema, @@ -87,6 +89,7 @@ const TABLES_RENAME_PATH = '/tables/rename'; const TABLES_UPDATE_FIELD_PATH = '/tables/updateField'; const TABLES_UPDATE_RECORD_PATH = '/tables/updateRecord'; const TABLES_REORDER_RECORDS_PATH = '/tables/reorderRecords'; +const TABLES_DUPLICATE_FIELD_PATH = '/tables/duplicateField'; const TABLES_DUPLICATE_RECORD_PATH = '/tables/duplicateRecord'; export const v2Contract: AnyContractRouter = { @@ -303,6 +306,16 @@ export const v2Contract: AnyContractRouter = { }) .input(reorderRecordsInputSchema) .output(reorderRecordsOkResponseSchema), + duplicateField: oc + .route({ + method: 'POST', + path: TABLES_DUPLICATE_FIELD_PATH, + successStatus: 200, + summary: 'Duplicate field', + tags: ['tables'], + }) + .input(duplicateFieldInputSchema) + .output(duplicateFieldOkResponseSchema), duplicateRecord: oc .route({ method: 'POST', diff --git a/packages/v2/contract-http/src/index.ts b/packages/v2/contract-http/src/index.ts index e4adc5b79..4acb34161 100644 --- a/packages/v2/contract-http/src/index.ts +++ b/packages/v2/contract-http/src/index.ts @@ -26,6 +26,7 @@ export * from './table/updateField'; export * from './table/updateRecord'; export * from './table/reorderRecords'; export * from './table/duplicateRecord'; +export * from './table/duplicateField'; export * from './table/paste'; export * from './table/clear'; export * from './table/deleteByRange'; diff --git a/packages/v2/contract-http/src/table/dto.ts b/packages/v2/contract-http/src/table/dto.ts index 7db197d2e..3def38393 100644 --- a/packages/v2/contract-http/src/table/dto.ts +++ b/packages/v2/contract-http/src/table/dto.ts @@ -103,6 +103,7 @@ const lookupOptionsSchema = z.object({ linkFieldId: z.string(), foreignTableId: z.string(), lookupFieldId: z.string(), + relationship: z.enum(['oneOne', 'manyMany', 'oneMany', 'manyOne']).optional(), filter: fieldConditionSchema.shape.filter, sort: fieldConditionSchema.shape.sort, limit: fieldConditionSchema.shape.limit, @@ -461,7 +462,7 @@ class FieldToDtoVisitor implements IFieldVisitor { dbFieldName: this.optionalDbFieldName(field), isPrimary: field.id().equals(this.primaryFieldId), ...(notNull ? { notNull } : {}), - ...(unique ? { unique } : {}), + unique, ...(isComputed ? { isComputed } : {}), ...(hasError ? { hasError } : {}), }; @@ -814,8 +815,17 @@ class FieldToDtoVisitor implements IFieldVisitor { visitLookupField(field: LookupField): Result { const lookupOptions = field.lookupOptionsDto(); - const baseField = this.baseField(field); + const isMultipleCellValueResult = field.isMultipleCellValue(); + const isMultipleCellValue = isMultipleCellValueResult.isOk() + ? isMultipleCellValueResult.value.toBoolean() + : undefined; + const relationship: 'oneOne' | 'manyMany' | 'oneMany' | 'manyOne' | undefined = + isMultipleCellValue == null ? undefined : isMultipleCellValue ? 'manyMany' : 'manyOne'; + const lookupOptionsWithRelationship = { + ...lookupOptions, + ...(baseField.hasError && relationship ? { relationship } : {}), + }; // For pending lookup fields, return minimal DTO with singleLineText as default type if (field.isPending()) { @@ -823,7 +833,7 @@ class FieldToDtoVisitor implements IFieldVisitor { ...baseField, type: 'singleLineText', isLookup: true, - lookupOptions, + lookupOptions: lookupOptionsWithRelationship, }); } @@ -836,7 +846,7 @@ class FieldToDtoVisitor implements IFieldVisitor { ...innerDto, ...baseField, isLookup: true, - lookupOptions, + lookupOptions: lookupOptionsWithRelationship, }); } diff --git a/packages/v2/contract-http/src/table/duplicateField.ts b/packages/v2/contract-http/src/table/duplicateField.ts new file mode 100644 index 000000000..c6439d09e --- /dev/null +++ b/packages/v2/contract-http/src/table/duplicateField.ts @@ -0,0 +1,59 @@ +import type { + DomainError, + DuplicateFieldResult, + IDuplicateFieldCommandInput, +} from '@teable/v2-core'; +import type { Result } from 'neverthrow'; +import { z } from 'zod'; + +import type { IDomainEventDto } from '../shared/domainEvent'; +import { domainEventDtoSchema, mapDomainEventToDto } from '../shared/domainEvent'; +import { + apiErrorResponseDtoSchema, + apiOkResponseDtoSchema, + type HttpErrorStatus, + type IApiErrorResponseDto, + type IApiOkResponseDto, + type IApiResponseDto, +} from '../shared/http'; +import type { ITableDto } from './dto'; +import { mapTableToDto, tableDtoSchema } from './dto'; + +export type IDuplicateFieldRequestDto = IDuplicateFieldCommandInput; + +export interface IDuplicateFieldResponseDataDto { + table: ITableDto; + newFieldId: string; + events: Array; +} + +export type IDuplicateFieldResponseDto = IApiResponseDto; + +export type IDuplicateFieldOkResponseDto = IApiOkResponseDto; +export type IDuplicateFieldErrorResponseDto = IApiErrorResponseDto; + +export type IDuplicateFieldEndpointResult = + | { status: 200; body: IDuplicateFieldOkResponseDto } + | { status: HttpErrorStatus; body: IDuplicateFieldErrorResponseDto }; + +export const duplicateFieldResponseDataSchema = z.object({ + table: tableDtoSchema, + newFieldId: z.string(), + events: z.array(domainEventDtoSchema), +}); + +export const duplicateFieldOkResponseSchema = apiOkResponseDtoSchema( + duplicateFieldResponseDataSchema +); + +export const duplicateFieldErrorResponseSchema = apiErrorResponseDtoSchema; + +export const mapDuplicateFieldResultToDto = ( + result: DuplicateFieldResult +): Result => { + return mapTableToDto(result.table).map((table) => ({ + table, + newFieldId: result.newField.id().toString(), + events: result.events.map(mapDomainEventToDto), + })); +}; diff --git a/packages/v2/contract-http/src/table/mapTableDtoToDomain.ts b/packages/v2/contract-http/src/table/mapTableDtoToDomain.ts index e6d6578f3..6fcba9787 100644 --- a/packages/v2/contract-http/src/table/mapTableDtoToDomain.ts +++ b/packages/v2/contract-http/src/table/mapTableDtoToDomain.ts @@ -82,6 +82,14 @@ import { sequenceResults } from '../shared/neverthrow'; import type { IFieldDto, ITableDto, IViewDto } from './dto'; type FormulaFieldDto = Extract; +type LookupRelationship = 'oneOne' | 'manyMany' | 'oneMany' | 'manyOne' | undefined; + +const relationshipToLookupMultiplicity = ( + relationship: LookupRelationship +): boolean | undefined => { + if (relationship == null) return undefined; + return relationship === 'manyOne' || relationship === 'oneOne' ? false : true; +}; const optional = ( raw: unknown, @@ -177,8 +185,11 @@ const mapFieldDtoToDomain = (dto: IFieldDto): Result => { ); } if (dto.isLookup && dto.lookupOptions) { + const isMultipleCellValue = relationshipToLookupMultiplicity( + dto.lookupOptions.relationship + ); return LookupOptions.create(dto.lookupOptions).andThen((lookupOptions) => - createLookupFieldPending({ id, name, lookupOptions }) + createLookupFieldPending({ id, name, lookupOptions, isMultipleCellValue }) .andThen((field) => applyFieldValidation(field, dto.notNull, dto.unique)) .andThen((field) => applyDbFieldName(field, dto.dbFieldName)) ); diff --git a/packages/v2/core/src/commands/CreateFieldCommand.spec.ts b/packages/v2/core/src/commands/CreateFieldCommand.spec.ts index 3de96da94..54b272c22 100644 --- a/packages/v2/core/src/commands/CreateFieldCommand.spec.ts +++ b/packages/v2/core/src/commands/CreateFieldCommand.spec.ts @@ -49,6 +49,76 @@ describe('CreateFieldCommand', () => { expect(command.field.type).toBe('singleLineText'); }); + it('accepts link input without lookupFieldId and keeps foreign table reference', () => { + const foreignTableId = `tbl${'c'.repeat(16)}`; + const commandResult = CreateFieldCommand.create({ + baseId, + tableId, + field: { + type: 'link', + name: 'Linked Records', + options: { + relationship: 'manyMany', + foreignTableId, + }, + }, + }); + + commandResult._unsafeUnwrap(); + const command = commandResult._unsafeUnwrap(); + expect(command.field.type).toBe('link'); + if (command.field.type !== 'link') return; + expect(command.field.options.lookupFieldId).toBeUndefined(); + + const refs = command.foreignTableReferences()._unsafeUnwrap(); + expect(refs).toHaveLength(1); + expect(refs[0]?.foreignTableId.toString()).toBe(foreignTableId); + }); + + it('accepts lookup field multiplicity in create input', () => { + const commandResult = CreateFieldCommand.create({ + baseId, + tableId, + field: { + type: 'lookup', + name: 'Lookup C', + isMultipleCellValue: false, + options: { + linkFieldId: `fld${'c'.repeat(16)}`, + foreignTableId: `tbl${'d'.repeat(16)}`, + lookupFieldId: `fld${'e'.repeat(16)}`, + }, + }, + }); + + const command = commandResult._unsafeUnwrap(); + expect(command.field.type).toBe('lookup'); + if (command.field.type !== 'lookup') return; + expect(command.field.isMultipleCellValue).toBe(false); + }); + + it('accepts aiConfig in create input for sidecar persistence flow', () => { + const commandResult = CreateFieldCommand.create({ + baseId, + tableId, + field: { + type: 'singleLineText', + name: 'AI Field', + aiConfig: { + type: 'summary', + sourceFieldId: `fld${'f'.repeat(16)}`, + }, + }, + }); + + const command = commandResult._unsafeUnwrap(); + expect(command.field.type).toBe('singleLineText'); + expect((command.field as { aiConfig?: unknown }).aiConfig).toEqual({ + type: 'summary', + sourceFieldId: `fld${'f'.repeat(16)}`, + }); + }); + it('accepts description on strict variants (formula)', () => { const commandResult = CreateFieldCommand.create({ baseId, @@ -436,6 +506,31 @@ describe('CreateFieldCommand', () => { }); }, }, + { + field: { + type: 'link', + name: 'Configured Link', + options: { + relationship: 'manyMany', + foreignTableId: tableId, + lookupFieldId: `fld${'c'.repeat(16)}`, + symmetricFieldId: `fld${'d'.repeat(16)}`, + fkHostTableName: `${baseId}.junction_custom_link`, + selfKeyName: `__fk_fld${'d'.repeat(16)}`, + foreignKeyName: `__fk_fld${'e'.repeat(16)}`, + }, + }, + assert: (field: unknown) => { + expect(field).toBeInstanceOf(LinkField); + const typed = field as LinkField; + expect(typed.relationship().toString()).toBe('manyMany'); + expect(typed.fkHostTableNameString()._unsafeUnwrap()).toBe( + `${baseId}.junction_custom_link` + ); + expect(typed.selfKeyNameString()._unsafeUnwrap()).toBe(`__fk_fld${'d'.repeat(16)}`); + expect(typed.foreignKeyNameString()._unsafeUnwrap()).toBe(`__fk_fld${'e'.repeat(16)}`); + }, + }, { field: { type: 'link', diff --git a/packages/v2/core/src/commands/CreateFieldCommand.ts b/packages/v2/core/src/commands/CreateFieldCommand.ts index 6c97ae139..3893609f9 100644 --- a/packages/v2/core/src/commands/CreateFieldCommand.ts +++ b/packages/v2/core/src/commands/CreateFieldCommand.ts @@ -1,4 +1,4 @@ -import { err } from 'neverthrow'; +import { err, ok } from 'neverthrow'; import type { Result } from 'neverthrow'; import { z } from 'zod'; @@ -14,6 +14,12 @@ export const createFieldInputSchema = z.object({ baseId: z.string(), tableId: z.string(), field: tableFieldInputSchema, + order: z + .object({ + viewId: z.string(), + orderIndex: z.number(), + }) + .optional(), }); export type ICreateFieldCommandInput = z.input; @@ -22,7 +28,11 @@ export class CreateFieldCommand extends TableUpdateCommand { private constructor( readonly baseId: BaseId, readonly tableId: TableId, - readonly field: z.output + readonly field: z.output, + readonly order?: { + viewId: string; + orderIndex: number; + } ) { super(baseId, tableId); } @@ -47,12 +57,21 @@ export class CreateFieldCommand extends TableUpdateCommand { return BaseId.create(parsed.data.baseId).andThen((baseId) => TableId.create(parsed.data.tableId).map( - (tableId) => new CreateFieldCommand(baseId, tableId, parsed.data.field) + (tableId) => new CreateFieldCommand(baseId, tableId, parsed.data.field, parsed.data.order) ) ); } foreignTableReferences(): Result, DomainError> { + if (this.field.type === 'link') { + const baseIdRaw = this.field.options.baseId; + return TableId.create(this.field.options.foreignTableId).andThen((foreignTableId) => + baseIdRaw + ? BaseId.create(baseIdRaw).map((baseId) => [{ foreignTableId, baseId }]) + : ok([{ foreignTableId }]) + ); + } + return resolveTableFieldInputName(this.field, []).andThen((resolved) => parseTableFieldSpec(resolved, { isPrimary: false }).andThen((spec) => spec.foreignTableReferences() diff --git a/packages/v2/core/src/commands/CreateFieldHandler.spec.ts b/packages/v2/core/src/commands/CreateFieldHandler.spec.ts index baf1177ee..a09f782aa 100644 --- a/packages/v2/core/src/commands/CreateFieldHandler.spec.ts +++ b/packages/v2/core/src/commands/CreateFieldHandler.spec.ts @@ -14,6 +14,7 @@ import { FieldId } from '../domain/table/fields/FieldId'; import { FieldName } from '../domain/table/fields/FieldName'; import type { FormulaField } from '../domain/table/fields/types/FormulaField'; import type { LinkField } from '../domain/table/fields/types/LinkField'; +import type { LookupField } from '../domain/table/fields/types/LookupField'; import type { ITableSpecVisitor } from '../domain/table/specs/ITableSpecVisitor'; import { Table } from '../domain/table/Table'; import { TableId } from '../domain/table/TableId'; @@ -313,4 +314,275 @@ describe('CreateFieldHandler', () => { expect(cellValueTypeResult.isOk()).toBe(true); cellValueTypeResult._unsafeUnwrap(); }); + + it('derives lookup multiplicity from oneMany link in domain layer', async () => { + const baseId = `bse${'a'.repeat(16)}`; + const hostTableId = `tbl${'b'.repeat(16)}`; + const foreignTableId = `tbl${'c'.repeat(16)}`; + const hostPrimaryId = `fld${'d'.repeat(16)}`; + const foreignPrimaryId = `fld${'e'.repeat(16)}`; + + const tableRepository = new InMemoryTableRepository(); + const schemaRepository = new FakeTableSchemaRepository(); + const eventBus = new FakeEventBus(); + const unitOfWork = new FakeUnitOfWork(); + const tableUpdateFlow = new TableUpdateFlow( + tableRepository, + schemaRepository, + eventBus, + unitOfWork + ); + const fieldCreationSideEffectService = new FieldCreationSideEffectService(tableUpdateFlow); + const foreignTableLoaderService = new ForeignTableLoaderService(tableRepository); + const handler = new CreateFieldHandler( + tableUpdateFlow, + fieldCreationSideEffectService, + foreignTableLoaderService + ); + + tableRepository.tables.push( + buildTable({ + baseId, + tableId: hostTableId, + tableName: 'Host', + primaryFieldId: hostPrimaryId, + }), + buildTable({ + baseId, + tableId: foreignTableId, + tableName: 'Foreign', + primaryFieldId: foreignPrimaryId, + }) + ); + + const createLink = CreateFieldCommand.create({ + baseId, + tableId: hostTableId, + field: { + type: 'link', + name: 'Host Link', + options: { + relationship: 'oneMany', + foreignTableId, + lookupFieldId: foreignPrimaryId, + }, + }, + })._unsafeUnwrap(); + const linkResult = await handler.handle(createContext(), createLink); + linkResult._unsafeUnwrap(); + + const hostAfterLink = tableRepository.tables.find( + (table) => table.id().toString() === hostTableId + ); + expect(hostAfterLink).toBeDefined(); + if (!hostAfterLink) return; + + const linkField = hostAfterLink + .getFields() + .find((field) => field.name().toString() === 'Host Link') as LinkField | undefined; + expect(linkField).toBeDefined(); + if (!linkField) return; + + const createLookup = CreateFieldCommand.create({ + baseId, + tableId: hostTableId, + field: { + type: 'lookup', + name: 'Lookup Name', + options: { + foreignTableId, + linkFieldId: linkField.id().toString(), + lookupFieldId: foreignPrimaryId, + }, + }, + })._unsafeUnwrap(); + const lookupResult = await handler.handle(createContext(), createLookup); + lookupResult._unsafeUnwrap(); + + const hostAfterLookup = tableRepository.tables.find( + (table) => table.id().toString() === hostTableId + ); + expect(hostAfterLookup).toBeDefined(); + if (!hostAfterLookup) return; + + const lookupField = hostAfterLookup + .getFields() + .find((field) => field.name().toString() === 'Lookup Name') as LookupField | undefined; + expect(lookupField?.type().toString()).toBe('lookup'); + expect(lookupField?.isMultipleCellValue()._unsafeUnwrap().isMultiple()).toBe(true); + }); + + it('derives lookup multiplicity as single for manyOne link in legacy mode', async () => { + const baseId = `bse${'f'.repeat(16)}`; + const hostTableId = `tbl${'g'.repeat(16)}`; + const foreignTableId = `tbl${'h'.repeat(16)}`; + const hostPrimaryId = `fld${'i'.repeat(16)}`; + const foreignPrimaryId = `fld${'j'.repeat(16)}`; + + const tableRepository = new InMemoryTableRepository(); + const schemaRepository = new FakeTableSchemaRepository(); + const eventBus = new FakeEventBus(); + const unitOfWork = new FakeUnitOfWork(); + const tableUpdateFlow = new TableUpdateFlow( + tableRepository, + schemaRepository, + eventBus, + unitOfWork + ); + const fieldCreationSideEffectService = new FieldCreationSideEffectService(tableUpdateFlow); + const foreignTableLoaderService = new ForeignTableLoaderService(tableRepository); + const handler = new CreateFieldHandler( + tableUpdateFlow, + fieldCreationSideEffectService, + foreignTableLoaderService + ); + + tableRepository.tables.push( + buildTable({ + baseId, + tableId: hostTableId, + tableName: 'Host', + primaryFieldId: hostPrimaryId, + }), + buildTable({ + baseId, + tableId: foreignTableId, + tableName: 'Foreign', + primaryFieldId: foreignPrimaryId, + }) + ); + + const createLink = CreateFieldCommand.create({ + baseId, + tableId: hostTableId, + field: { + type: 'link', + name: 'Host Link', + options: { + relationship: 'manyOne', + foreignTableId, + lookupFieldId: foreignPrimaryId, + }, + }, + })._unsafeUnwrap(); + const linkResult = await handler.handle(createContext(), createLink); + linkResult._unsafeUnwrap(); + + const hostAfterLink = tableRepository.tables.find( + (table) => table.id().toString() === hostTableId + ); + expect(hostAfterLink).toBeDefined(); + if (!hostAfterLink) return; + + const linkField = hostAfterLink + .getFields() + .find((field) => field.name().toString() === 'Host Link') as LinkField | undefined; + expect(linkField).toBeDefined(); + if (!linkField) return; + + const createLookup = CreateFieldCommand.create({ + baseId, + tableId: hostTableId, + field: { + type: 'lookup', + name: 'Lookup Name', + legacyMultiplicityDerivation: true, + options: { + foreignTableId, + linkFieldId: linkField.id().toString(), + lookupFieldId: foreignPrimaryId, + }, + }, + })._unsafeUnwrap(); + const lookupResult = await handler.handle(createContext(), createLookup); + lookupResult._unsafeUnwrap(); + + const hostAfterLookup = tableRepository.tables.find( + (table) => table.id().toString() === hostTableId + ); + expect(hostAfterLookup).toBeDefined(); + if (!hostAfterLookup) return; + + const lookupField = hostAfterLookup + .getFields() + .find((field) => field.name().toString() === 'Lookup Name') as LookupField | undefined; + expect(lookupField?.type().toString()).toBe('lookup'); + expect(lookupField?.isMultipleCellValue()._unsafeUnwrap().isMultiple()).toBe(false); + }); + + it('allows cross-base conditional lookup creation', async () => { + const hostBaseId = `bse${'a'.repeat(16)}`; + const foreignBaseId = `bse${'b'.repeat(16)}`; + const hostTableId = `tbl${'c'.repeat(16)}`; + const foreignTableId = `tbl${'d'.repeat(16)}`; + const hostPrimaryId = `fld${'e'.repeat(16)}`; + const foreignPrimaryId = `fld${'f'.repeat(16)}`; + + const tableRepository = new InMemoryTableRepository(); + const schemaRepository = new FakeTableSchemaRepository(); + const eventBus = new FakeEventBus(); + const unitOfWork = new FakeUnitOfWork(); + const tableUpdateFlow = new TableUpdateFlow( + tableRepository, + schemaRepository, + eventBus, + unitOfWork + ); + const fieldCreationSideEffectService = new FieldCreationSideEffectService(tableUpdateFlow); + const foreignTableLoaderService = new ForeignTableLoaderService(tableRepository); + const handler = new CreateFieldHandler( + tableUpdateFlow, + fieldCreationSideEffectService, + foreignTableLoaderService + ); + + tableRepository.tables.push( + buildTable({ + baseId: hostBaseId, + tableId: hostTableId, + tableName: 'Host', + primaryFieldId: hostPrimaryId, + }), + buildTable({ + baseId: foreignBaseId, + tableId: foreignTableId, + tableName: 'Foreign', + primaryFieldId: foreignPrimaryId, + }) + ); + + const commandResult = CreateFieldCommand.create({ + baseId: hostBaseId, + tableId: hostTableId, + field: { + type: 'conditionalLookup', + name: 'Cross Base Amounts', + options: { + foreignTableId, + lookupFieldId: foreignPrimaryId, + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: foreignPrimaryId, operator: 'is', value: 'A' }], + }, + }, + }, + }, + }); + commandResult._unsafeUnwrap(); + + const result = await handler.handle(createContext(), commandResult._unsafeUnwrap()); + result._unsafeUnwrap(); + + const updatedTable = tableRepository.tables.find( + (table) => table.id().toString() === hostTableId + ); + expect(updatedTable).toBeDefined(); + if (!updatedTable) return; + + const conditionalLookup = updatedTable + .getFields() + .find((field) => field.name().toString() === 'Cross Base Amounts'); + expect(conditionalLookup?.type().toString()).toBe('conditionalLookup'); + }); }); diff --git a/packages/v2/core/src/commands/CreateFieldHandler.ts b/packages/v2/core/src/commands/CreateFieldHandler.ts index cf1381d33..f00c39ddf 100644 --- a/packages/v2/core/src/commands/CreateFieldHandler.ts +++ b/packages/v2/core/src/commands/CreateFieldHandler.ts @@ -7,11 +7,14 @@ import { ForeignTableLoaderService } from '../application/services/ForeignTableL import { TableUpdateFlow } from '../application/services/TableUpdateFlow'; import { domainError, type DomainError } from '../domain/shared/DomainError'; import type { IDomainEvent } from '../domain/shared/DomainEvent'; +import { DbFieldName } from '../domain/table/fields/DbFieldName'; import type { Field } from '../domain/table/fields/Field'; import type { Table } from '../domain/table/Table'; +import { ViewId } from '../domain/table/views/ViewId'; import * as ExecutionContextPort from '../ports/ExecutionContext'; import { v2CoreTokens } from '../ports/tokens'; import { TraceSpan } from '../ports/TraceSpan'; +import type { ResolvedTableFieldInput } from '../schemas/field'; import { CommandHandler, type ICommandHandler } from './CommandHandler'; import { CreateFieldCommand } from './CreateFieldCommand'; import { parseTableFieldSpec, resolveTableFieldInputName } from './TableFieldSpecs'; @@ -48,7 +51,7 @@ export class CreateFieldHandler implements ICommandHandler(async function* () { const foreignTableReferences = yield* command.foreignTableReferences(); const foreignTables = yield* await handler.foreignTableLoaderService.load(context, { - baseId: command.baseId, + // Foreign references may point to tables in other bases (e.g. cross-base lookup). references: foreignTableReferences, }); let createdField: Field | undefined; @@ -61,16 +64,40 @@ export class CreateFieldHandler implements ICommandHandler - parseTableFieldSpec(resolved, { isPrimary: false }) + }).andThen((resolved) => { + const normalized = handler.populateLinkLookupFieldId(resolved, foreignTables); + return parseTableFieldSpec(normalized, { isPrimary: false }) .andThen((spec) => spec.createField({ baseId: command.baseId, tableId: command.tableId }) ) .andThen((field) => { + if (normalized.dbFieldName) { + const dbFieldNameResult = DbFieldName.rehydrate(normalized.dbFieldName).andThen( + (dbFieldName) => field.setDbFieldName(dbFieldName) + ); + if (dbFieldNameResult.isErr()) { + return err(dbFieldNameResult.error); + } + } createdField = field; - return table.update((mutator) => mutator.addField(field, { foreignTables })); - }) - ); + if (!command.order) { + return table.update((mutator) => mutator.addField(field, { foreignTables })); + } + + const order = command.order; + return ViewId.create(order.viewId).andThen((viewId) => + table.update((mutator) => + mutator.addField(field, { + foreignTables, + viewOrder: { + viewId, + order: order.orderIndex, + }, + }) + ) + ); + }); + }); }, { hooks: { @@ -93,4 +120,28 @@ export class CreateFieldHandler implements ICommandHandler + ): ResolvedTableFieldInput { + if (field.type !== 'link' || field.options.lookupFieldId != null) { + return field; + } + + const foreignTable = foreignTables.find( + (table) => table.id().toString() === field.options.foreignTableId + ); + if (!foreignTable) { + return field; + } + + return { + ...field, + options: { + ...field.options, + lookupFieldId: foreignTable.primaryFieldId().toString(), + }, + }; + } } diff --git a/packages/v2/core/src/commands/CreateTablesHandler.spec.ts b/packages/v2/core/src/commands/CreateTablesHandler.spec.ts index 2f05087fa..c044949e2 100644 --- a/packages/v2/core/src/commands/CreateTablesHandler.spec.ts +++ b/packages/v2/core/src/commands/CreateTablesHandler.spec.ts @@ -6,17 +6,22 @@ import { FieldCreationSideEffectService } from '../application/services/FieldCre import { ForeignTableLoaderService } from '../application/services/ForeignTableLoaderService'; import { TableCreationService } from '../application/services/TableCreationService'; import { TableUpdateFlow } from '../application/services/TableUpdateFlow'; +import { BaseId } from '../domain/base/BaseId'; import { ActorId } from '../domain/shared/ActorId'; import { domainError, type DomainError } from '../domain/shared/DomainError'; import type { IDomainEvent } from '../domain/shared/DomainEvent'; import type { ISpecification } from '../domain/shared/specification/ISpecification'; +import { FieldId } from '../domain/table/fields/FieldId'; +import { FieldName } from '../domain/table/fields/FieldName'; import type { RecordId } from '../domain/table/records/RecordId'; import type { RecordUpdateResult } from '../domain/table/records/RecordUpdateResult'; import type { ITableRecordConditionSpecVisitor } from '../domain/table/records/specs/ITableRecordConditionSpecVisitor'; import type { ICellValueSpec } from '../domain/table/records/specs/values/ICellValueSpecVisitor'; import type { TableRecord } from '../domain/table/records/TableRecord'; import type { ITableSpecVisitor } from '../domain/table/specs/ITableSpecVisitor'; -import type { Table } from '../domain/table/Table'; +import { Table } from '../domain/table/Table'; +import { TableId } from '../domain/table/TableId'; +import { TableName } from '../domain/table/TableName'; import type { TableSortKey } from '../domain/table/TableSortKey'; import type { IEventBus } from '../ports/EventBus'; import type { IExecutionContext, IUnitOfWorkTransaction } from '../ports/ExecutionContext'; @@ -40,6 +45,29 @@ const createContext = (): IExecutionContext => { return { actorId: actorIdResult._unsafeUnwrap() }; }; +const buildTable = (params: { + baseId: string; + tableId: string; + tableName: string; + primaryFieldId: string; +}): Table => { + return Table.builder() + .withId(TableId.create(params.tableId)._unsafeUnwrap()) + .withBaseId(BaseId.create(params.baseId)._unsafeUnwrap()) + .withName(TableName.create(params.tableName)._unsafeUnwrap()) + .field() + .singleLineText() + .withId(FieldId.create(params.primaryFieldId)._unsafeUnwrap()) + .withName(FieldName.create('Name')._unsafeUnwrap()) + .primary() + .done() + .view() + .defaultGrid() + .done() + .build() + ._unsafeUnwrap(); +}; + class FakeTableRepository implements ITableRepository { inserted: Table[] = []; updated: Table[] = []; @@ -435,4 +463,81 @@ describe('CreateTablesHandler', () => { expect(recordAValue).toBe('Alpha'); expect(recordBValue).toBe('Beta'); }); + + it('allows creating tables that link to external cross-base tables', async () => { + const hostBaseId = `bse${'f'.repeat(16)}`; + const foreignBaseId = `bse${'g'.repeat(16)}`; + const foreignTableId = `tbl${'h'.repeat(16)}`; + const foreignPrimaryId = `fld${'i'.repeat(16)}`; + const hostTableId = `tbl${'j'.repeat(16)}`; + const hostPrimaryId = `fld${'k'.repeat(16)}`; + const hostLinkId = `fld${'l'.repeat(16)}`; + + const commandResult = CreateTablesCommand.create({ + baseId: hostBaseId, + tables: [ + { + tableId: hostTableId, + name: 'Host Table', + fields: [ + { type: 'singleLineText', id: hostPrimaryId, name: 'Name', isPrimary: true }, + { + type: 'link', + id: hostLinkId, + name: 'Cross Base Link', + options: { + baseId: foreignBaseId, + relationship: 'manyOne', + foreignTableId, + lookupFieldId: foreignPrimaryId, + }, + }, + ], + views: [{ type: 'grid' }], + }, + ], + }); + + const tableRepository = new FakeTableRepository(); + tableRepository.inserted.push( + buildTable({ + baseId: foreignBaseId, + tableId: foreignTableId, + tableName: 'Foreign Table', + primaryFieldId: foreignPrimaryId, + }) + ); + const schemaRepository = new FakeTableSchemaRepository(); + const recordRepository = new FakeTableRecordRepository(); + const eventBus = new FakeEventBus(); + const unitOfWork = new FakeUnitOfWork(); + const tableUpdateFlow = new TableUpdateFlow( + tableRepository, + schemaRepository, + eventBus, + unitOfWork + ); + const fieldCreationSideEffectService = new FieldCreationSideEffectService(tableUpdateFlow); + const foreignTableLoaderService = new ForeignTableLoaderService(tableRepository); + const tableCreationService = new TableCreationService( + tableRepository, + schemaRepository, + fieldCreationSideEffectService + ); + const handler = new CreateTablesHandler( + tableRepository, + recordRepository, + foreignTableLoaderService, + tableCreationService, + eventBus, + unitOfWork + ); + + const result = await handler.handle(createContext(), commandResult._unsafeUnwrap()); + result._unsafeUnwrap(); + + expect(tableRepository.inserted.some((table) => table.id().toString() === hostTableId)).toBe( + true + ); + }); }); diff --git a/packages/v2/core/src/commands/CreateTablesHandler.ts b/packages/v2/core/src/commands/CreateTablesHandler.ts index bd2e61b40..812fc32b5 100644 --- a/packages/v2/core/src/commands/CreateTablesHandler.ts +++ b/packages/v2/core/src/commands/CreateTablesHandler.ts @@ -282,7 +282,8 @@ export class CreateTablesHandler // Load external/foreign tables const externalTables = yield* await handler.foreignTableLoaderService.load(context, { - baseId: command.baseId, + // Cross-base references are allowed for external tables. + // Do not constrain by host baseId here. references: externalReferences, }); diff --git a/packages/v2/core/src/commands/DuplicateFieldCommand.spec.ts b/packages/v2/core/src/commands/DuplicateFieldCommand.spec.ts index 05c2a21b8..64ec63552 100644 --- a/packages/v2/core/src/commands/DuplicateFieldCommand.spec.ts +++ b/packages/v2/core/src/commands/DuplicateFieldCommand.spec.ts @@ -30,6 +30,7 @@ describe('DuplicateFieldCommand', () => { fieldId: 'fldcccccccccccccccc', includeRecordValues: false, newFieldName: 'Custom Name', + viewId: 'viwaaaaaaaaaaaaaaaa', }; const result = DuplicateFieldCommand.create(input); @@ -38,6 +39,7 @@ describe('DuplicateFieldCommand', () => { if (result.isOk()) { expect(result.value.includeRecordValues).toBe(false); expect(result.value.newFieldName).toBe('Custom Name'); + expect(result.value.viewId?.toString()).toBe(input.viewId); } }); diff --git a/packages/v2/core/src/commands/DuplicateFieldCommand.ts b/packages/v2/core/src/commands/DuplicateFieldCommand.ts index ac4dfbe0d..0897bcad8 100644 --- a/packages/v2/core/src/commands/DuplicateFieldCommand.ts +++ b/packages/v2/core/src/commands/DuplicateFieldCommand.ts @@ -7,6 +7,7 @@ import { domainError, type DomainError } from '../domain/shared/DomainError'; import type { LinkForeignTableReference } from '../domain/table/fields/visitors/LinkForeignTableReferenceVisitor'; import { FieldId } from '../domain/table/fields/FieldId'; import { TableId } from '../domain/table/TableId'; +import { ViewId } from '../domain/table/views/ViewId'; import { TableUpdateCommand } from './TableUpdateCommand'; export const duplicateFieldInputSchema = z.object({ @@ -15,6 +16,7 @@ export const duplicateFieldInputSchema = z.object({ fieldId: z.string(), includeRecordValues: z.boolean().default(true), newFieldName: z.string().optional(), + viewId: z.string().optional(), }); export type IDuplicateFieldCommandInput = z.input; @@ -25,7 +27,8 @@ export class DuplicateFieldCommand extends TableUpdateCommand { readonly tableId: TableId, readonly fieldId: FieldId, readonly includeRecordValues: boolean, - readonly newFieldName: string | undefined + readonly newFieldName: string | undefined, + readonly viewId: ViewId | undefined ) { super(baseId, tableId); } @@ -42,15 +45,29 @@ export class DuplicateFieldCommand extends TableUpdateCommand { return BaseId.create(parsed.data.baseId).andThen((baseId) => TableId.create(parsed.data.tableId).andThen((tableId) => - FieldId.create(parsed.data.fieldId).map( - (fieldId) => - new DuplicateFieldCommand( - baseId, - tableId, - fieldId, - parsed.data.includeRecordValues, - parsed.data.newFieldName - ) + FieldId.create(parsed.data.fieldId).andThen((fieldId) => + parsed.data.viewId + ? ViewId.create(parsed.data.viewId).map( + (viewId) => + new DuplicateFieldCommand( + baseId, + tableId, + fieldId, + parsed.data.includeRecordValues, + parsed.data.newFieldName, + viewId + ) + ) + : ok( + new DuplicateFieldCommand( + baseId, + tableId, + fieldId, + parsed.data.includeRecordValues, + parsed.data.newFieldName, + undefined + ) + ) ) ) ); diff --git a/packages/v2/core/src/commands/DuplicateFieldHandler.ts b/packages/v2/core/src/commands/DuplicateFieldHandler.ts index dd64aaec5..ed6b85e4f 100644 --- a/packages/v2/core/src/commands/DuplicateFieldHandler.ts +++ b/packages/v2/core/src/commands/DuplicateFieldHandler.ts @@ -83,21 +83,25 @@ export class DuplicateFieldHandler const resolvedName = generateUniqueName(baseName, existingNames); const newFieldName = yield* FieldName.create(resolvedName); - // Clone the source field with new ID and name - const clonedField = yield* field.duplicate({ - newId: newFieldId, - newName: newFieldName, - baseId: command.baseId, - tableId: command.tableId, - }); - newField = clonedField; - // Update table with duplicated field // Note: Value duplication happens in the repository visitor (TableSchemaUpdateVisitor) // when it visits the TableDuplicateFieldSpec const updated = yield* table.update((mutator) => - mutator.duplicateField(sourceField!, clonedField, command.includeRecordValues) + mutator.duplicateField( + sourceField!, + newFieldId, + newFieldName, + command.includeRecordValues, + { + targetViewId: command.viewId, + } + ) ); + const duplicatedFieldResult = updated.table.getField((f) => f.id().equals(newFieldId)); + if (duplicatedFieldResult.isErr()) { + return err(duplicatedFieldResult.error); + } + newField = duplicatedFieldResult.value; return ok(updated); }), { diff --git a/packages/v2/core/src/commands/FieldValidation.ts b/packages/v2/core/src/commands/FieldValidation.ts index f192c2a4a..b9d2538ad 100644 --- a/packages/v2/core/src/commands/FieldValidation.ts +++ b/packages/v2/core/src/commands/FieldValidation.ts @@ -31,7 +31,6 @@ const notNullValidationFieldTypes = new Set([ 'date', 'rating', 'attachment', - 'link', ]); export const isComputedFieldType = (fieldType: FieldTypeValue): boolean => diff --git a/packages/v2/core/src/commands/TableFieldSpecs.spec.ts b/packages/v2/core/src/commands/TableFieldSpecs.spec.ts index 1aa2f1ec8..50617b895 100644 --- a/packages/v2/core/src/commands/TableFieldSpecs.spec.ts +++ b/packages/v2/core/src/commands/TableFieldSpecs.spec.ts @@ -4,6 +4,7 @@ import { tableI18nKeys } from '@teable/i18n-keys'; import { BaseId } from '../domain/base/BaseId'; import { FieldId } from '../domain/table/fields/FieldId'; import { FieldName } from '../domain/table/fields/FieldName'; +import { ConditionalLookupField } from '../domain/table/fields/types/ConditionalLookupField'; import { Table } from '../domain/table/Table'; import { TableName } from '../domain/table/TableName'; import { TableId } from '../domain/table/TableId'; @@ -289,6 +290,46 @@ describe('TableFieldSpecs', () => { } }); + it('preserves conditional lookup inner options patch in create spec', () => { + const foreignTableId = `tbl${'b'.repeat(16)}`; + const lookupFieldId = `fld${'a'.repeat(16)}`; + + const specResult = parseSpec({ + type: 'conditionalLookup', + name: 'Conditional Currency', + options: { + foreignTableId, + lookupFieldId, + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: lookupFieldId, operator: 'is', value: 'active' }], + }, + }, + }, + innerOptions: { + formatting: { + type: 'currency', + precision: 1, + symbol: '¥', + }, + }, + }); + + expect(specResult.isOk()).toBe(true); + const fieldResult = specResult._unsafeUnwrap().createField(); + expect(fieldResult.isOk()).toBe(true); + const field = fieldResult._unsafeUnwrap(); + expect(field).toBeInstanceOf(ConditionalLookupField); + expect((field as ConditionalLookupField).innerOptionsPatch()).toEqual({ + formatting: { + type: 'currency', + precision: 1, + symbol: '¥', + }, + }); + }); + it('collects foreign table references from specs', () => { const linkSpec = parseSpec({ type: 'link', @@ -319,4 +360,27 @@ describe('TableFieldSpecs', () => { const field = spec.createField()._unsafeUnwrap(); expect(field.id()).toBeInstanceOf(FieldId); }); + + it('applies aiConfig when creating field from spec', () => { + const aiConfig = { + type: 'summary', + modelKey: 'openai@gpt-4o@gpt', + sourceFieldId: `fld${'z'.repeat(16)}`, + }; + + const spec = parseSpec({ + type: 'singleLineText', + name: 'AI Text', + aiConfig, + })._unsafeUnwrap(); + + const field = spec + .createField({ + baseId: BaseId.create(`bse${'e'.repeat(16)}`)._unsafeUnwrap(), + tableId: TableId.create(`tbl${'f'.repeat(16)}`)._unsafeUnwrap(), + }) + ._unsafeUnwrap(); + + expect(field.aiConfig()).toEqual(aiConfig); + }); }); diff --git a/packages/v2/core/src/commands/TableFieldSpecs.ts b/packages/v2/core/src/commands/TableFieldSpecs.ts index ad3f8a8b5..7c8c962e6 100644 --- a/packages/v2/core/src/commands/TableFieldSpecs.ts +++ b/packages/v2/core/src/commands/TableFieldSpecs.ts @@ -143,8 +143,6 @@ const derivedFieldNameWithTranslation = ( options: ResolveTableFieldNameOptions ): string | undefined => { const t = options.t; - if (!t) return; - const foreignTables = options.foreignTables; const hostTable = options.hostTable; @@ -163,9 +161,20 @@ const derivedFieldNameWithTranslation = ( } ).options; const foreignTable = findTableById(foreignTables, opts?.foreignTableId); - const lookupFieldName = findFieldNameById(foreignTable, opts?.lookupFieldId); + const lookupFieldName = findFieldNameById(foreignTable, opts?.lookupFieldId) ?? 'Name'; const linkFieldName = findFieldNameById(hostTable, opts?.linkFieldId); - if (!lookupFieldName || !linkFieldName) return; + const tableName = foreignTable?.name().toString(); + if (!t) { + return tableName + ? `${lookupFieldName} (from ${tableName})` + : `${lookupFieldName} (from ${linkFieldName ?? 'Link'})`; + } + if (!linkFieldName) { + if (tableName) { + return `${lookupFieldName} (from ${tableName})`; + } + return; + } return translateOrFallback(t, tableI18nKeys.field.default.lookup.title, 'Lookup', { lookupFieldName, linkFieldName, @@ -180,6 +189,13 @@ const derivedFieldNameWithTranslation = ( const foreignTable = findTableById(foreignTables, cfg?.foreignTableId); const lookupFieldName = findFieldNameById(foreignTable, cfg?.lookupFieldId); const linkFieldName = findFieldNameById(hostTable, cfg?.linkFieldId); + const tableName = foreignTable?.name().toString(); + if (!t) { + if (lookupFieldName && tableName) { + return `${lookupFieldName} Rollup (from ${tableName})`; + } + return 'Rollup'; + } if (lookupFieldName && linkFieldName) { return translateOrFallback(t, tableI18nKeys.field.default.rollup.title, 'Rollup', { lookupFieldName, @@ -195,6 +211,9 @@ const derivedFieldNameWithTranslation = ( const lookupFieldName = findFieldNameById(foreignTable, opts?.lookupFieldId); const tableName = foreignTable?.name().toString(); if (!lookupFieldName || !tableName) return; + if (!t) { + return `${lookupFieldName} (from ${tableName})`; + } return translateOrFallback( t, tableI18nKeys.field.default.conditionalLookup.title, @@ -209,6 +228,9 @@ const derivedFieldNameWithTranslation = ( const lookupFieldName = findFieldNameById(foreignTable, cfg?.lookupFieldId); const tableName = foreignTable?.name().toString(); if (!lookupFieldName || !tableName) return; + if (!t) { + return `${lookupFieldName} Rollup (from ${tableName})`; + } return translateOrFallback( t, tableI18nKeys.field.default.conditionalRollup.title, @@ -226,14 +248,13 @@ const defaultFieldName = ( options?: ResolveTableFieldNameOptions ): string => { const t = options?.t; + const derived = derivedFieldNameWithTranslation(field, options ?? {}); + if (derived) return derived; // Keep legacy behavior when translation isn't provided. if (!t && field.isPrimary === true) return 'Name'; if (t) { - const derived = derivedFieldNameWithTranslation(field, options ?? {}); - if (derived) return derived; - switch (field.type) { case 'singleLineText': return translateOrFallback(t, tableI18nKeys.field.default.singleLineText.title, 'Label'); @@ -321,7 +342,7 @@ const defaultFieldName = ( case 'lastModifiedBy': return 'Last Modified By'; case 'autoNumber': - return 'Auto Number'; + return 'ID'; case 'button': return 'Button'; case 'formula': @@ -418,6 +439,44 @@ class CreateTableFieldWithDescriptionSpec implements ICreateTableFieldSpec { } } +class CreateTableFieldWithAiConfigSpec implements ICreateTableFieldSpec { + constructor( + private readonly spec: ICreateTableFieldSpec, + private readonly aiConfig: unknown | null | undefined, + private readonly fieldName: string + ) {} + + applyTo(builder: TableBuilder): void { + this.spec.applyTo(builder); + } + + createField(params?: { baseId?: BaseId; tableId?: TableId }): Result { + return this.spec + .createField(params) + .andThen((field) => + this.aiConfig === undefined ? ok(field) : field.setAiConfig(this.aiConfig).map(() => field) + ); + } + + foreignTableReferences(): Result, DomainError> { + return this.spec.foreignTableReferences(); + } + + applyPostBuild(table: Table): Result { + const applyInner = this.spec.applyPostBuild ? this.spec.applyPostBuild(table) : ok(undefined); + + if (this.aiConfig === undefined) { + return applyInner; + } + + return applyInner.andThen(() => + table + .getField((field) => field.name().toString() === this.fieldName) + .andThen((field) => field.setAiConfig(this.aiConfig)) + ); + } +} + const withFieldDescription = ( spec: ICreateTableFieldSpec, description: string | null | undefined, @@ -426,6 +485,14 @@ const withFieldDescription = ( return new CreateTableFieldWithDescriptionSpec(spec, description ?? null, fieldName); }; +const withFieldAiConfig = ( + spec: ICreateTableFieldSpec, + aiConfig: unknown | null | undefined, + fieldName: string +): ICreateTableFieldSpec => { + return new CreateTableFieldWithAiConfigSpec(spec, aiConfig, fieldName); +}; + const uniqueForeignTableReferences = ( refs: ReadonlyArray ): ReadonlyArray => { @@ -999,6 +1066,8 @@ class CreateLookupFieldSpec implements ICreateTableFieldSpec { private readonly filter: unknown, private readonly sort: unknown, private readonly limit: number | undefined, + private readonly innerOptionsPatch: Readonly> | undefined, + private readonly legacyMultiplicityDerivation: boolean, private readonly isMultipleCellValue: boolean | undefined, private readonly notNull: FieldNotNull, private readonly unique: FieldUnique @@ -1015,6 +1084,8 @@ class CreateLookupFieldSpec implements ICreateTableFieldSpec { filter?: unknown; sort?: unknown; limit?: number; + innerOptionsPatch?: Readonly>; + legacyMultiplicityDerivation?: boolean; isMultipleCellValue?: boolean; notNull: FieldNotNull; unique: FieldUnique; @@ -1029,6 +1100,8 @@ class CreateLookupFieldSpec implements ICreateTableFieldSpec { options.filter, options.sort, options.limit, + options.innerOptionsPatch, + options.legacyMultiplicityDerivation === true, options.isMultipleCellValue, options.notNull, options.unique @@ -1059,6 +1132,8 @@ class CreateLookupFieldSpec implements ICreateTableFieldSpec { id, name: this.name, lookupOptions, + innerOptionsPatch: this.innerOptionsPatch, + legacyMultiplicityDerivation: this.legacyMultiplicityDerivation, isMultipleCellValue: this.isMultipleCellValue, notNull: this.notNull, unique: this.unique, @@ -1207,7 +1282,8 @@ class CreateConditionalLookupFieldSpec implements ICreateTableFieldSpec { private constructor( private readonly id: FieldId | undefined, private readonly name: FieldName, - private readonly conditionalLookupOptions: ConditionalLookupOptions + private readonly conditionalLookupOptions: ConditionalLookupOptions, + private readonly innerOptionsPatch: Readonly> | undefined ) {} static create( @@ -1216,12 +1292,14 @@ class CreateConditionalLookupFieldSpec implements ICreateTableFieldSpec { options: { isPrimary: boolean; conditionalLookupOptions: ConditionalLookupOptions; + innerOptionsPatch?: Readonly>; } ): CreateConditionalLookupFieldSpec { return new CreateConditionalLookupFieldSpec( id, name, - options.conditionalLookupOptions + options.conditionalLookupOptions, + options.innerOptionsPatch ).withPrimary(options.isPrimary); } @@ -1243,6 +1321,7 @@ class CreateConditionalLookupFieldSpec implements ICreateTableFieldSpec { id, name: this.name, conditionalLookupOptions: this.conditionalLookupOptions, + innerOptionsPatch: this.innerOptionsPatch, }) ); } @@ -2269,7 +2348,7 @@ export const parseTableFieldSpec = ( CreateFormulaFieldSpec.create(id, name, { isPrimary: options.isPrimary, expression, - timeZone, + timeZone: timeZone ?? TimeZone.default(), formatting, showAs, resultType, @@ -2326,6 +2405,13 @@ export const parseTableFieldSpec = ( filter: field.options.filter, sort: field.options.sort, limit: field.options.limit, + innerOptionsPatch: + field.innerOptions && + typeof field.innerOptions === 'object' && + !Array.isArray(field.innerOptions) + ? (field.innerOptions as Record) + : undefined, + legacyMultiplicityDerivation: field.legacyMultiplicityDerivation === true, isMultipleCellValue: 'isMultipleCellValue' in field && typeof field.isMultipleCellValue === 'boolean' ? field.isMultipleCellValue @@ -2504,11 +2590,23 @@ export const parseTableFieldSpec = ( CreateConditionalLookupFieldSpec.create(id, name, { isPrimary: options.isPrimary, conditionalLookupOptions, + innerOptionsPatch: + field.innerOptions && + typeof field.innerOptions === 'object' && + !Array.isArray(field.innerOptions) + ? (field.innerOptions as Record) + : undefined, }) ) ) .exhaustive() - .map((spec) => withFieldDescription(spec, field.description, field.name)) + .map((spec) => + withFieldAiConfig( + withFieldDescription(spec, field.description, field.name), + field.aiConfig, + field.name + ) + ) ) ) ); diff --git a/packages/v2/core/src/commands/TableFieldUpdateSpecs.ts b/packages/v2/core/src/commands/TableFieldUpdateSpecs.ts index a81d9db46..cfdbd068a 100644 --- a/packages/v2/core/src/commands/TableFieldUpdateSpecs.ts +++ b/packages/v2/core/src/commands/TableFieldUpdateSpecs.ts @@ -1387,6 +1387,7 @@ class UpdateConditionalLookupFieldSpec implements IUpdateTableFieldSpec { return err(nextInnerFieldResult.error); } const nextInnerField = nextInnerFieldResult.value; + const nextInnerOptionsPatch = this.resolveNextInnerOptionsPatch(params.currentField); if (nextInnerField) { return ConditionalLookupField.create({ @@ -1396,6 +1397,7 @@ class UpdateConditionalLookupFieldSpec implements IUpdateTableFieldSpec { conditionalLookupOptions: params.nextOptions, isMultipleCellValue: params.isMultipleCellValue, dependencies: params.currentField.dependencies(), + innerOptionsPatch: nextInnerOptionsPatch, }); } @@ -1405,9 +1407,31 @@ class UpdateConditionalLookupFieldSpec implements IUpdateTableFieldSpec { conditionalLookupOptions: params.nextOptions, isMultipleCellValue: params.isMultipleCellValue, dependencies: params.currentField.dependencies(), + innerOptionsPatch: nextInnerOptionsPatch, }); } + private resolveNextInnerOptionsPatch( + currentField: ConditionalLookupField + ): Readonly> | undefined { + const currentPatch = currentField.innerOptionsPatch(); + const hasInnerTypeUpdate = this.innerTypeValue !== undefined; + const hasInnerOptionsUpdate = this.innerOptionsValue !== undefined; + + if (hasInnerTypeUpdate) { + return hasInnerOptionsUpdate ? this.innerOptionsValue : undefined; + } + + if (hasInnerOptionsUpdate) { + return { + ...(currentPatch ?? {}), + ...this.innerOptionsValue, + }; + } + + return currentPatch; + } + private buildUpdatedInnerField( currentField: ConditionalLookupField, nextOptions: ConditionalLookupOptions @@ -2122,6 +2146,18 @@ class UpdateFormulaFieldSpec implements IUpdateTableFieldSpec { UpdateFormulaTimeZoneSpec.create(currentField.id(), currentTimeZone, this.timeZoneValue) ); } + } else { + const currentTimeZone = currentField.timeZone(); + const touchedFormulaOptions = + this.expressionValue !== undefined || + this.formattingValue !== undefined || + this.showAsValue !== undefined || + this.shouldClearShowAs; + if (!currentTimeZone && touchedFormulaOptions) { + specs.push( + UpdateFormulaTimeZoneSpec.create(currentField.id(), currentTimeZone, TimeZone.default()) + ); + } } if (this.formattingValue !== undefined) { diff --git a/packages/v2/core/src/domain/formula/visitor.ts b/packages/v2/core/src/domain/formula/visitor.ts index 6c9bc36de..ec0d4cf62 100644 --- a/packages/v2/core/src/domain/formula/visitor.ts +++ b/packages/v2/core/src/domain/formula/visitor.ts @@ -89,14 +89,9 @@ export class FormulaTypeVisitor if (rightResult.isErr()) return err(rightResult.error); const valueType = this.getBinaryOpValueType(ctx, leftResult.value, rightResult.value); - // Comparison operators always return a single boolean value, - // even when comparing arrays (the array is unwrapped to its first element in SQL). - // Logical operators (||, &&) also return single boolean. - const isComparisonOrLogical = this.isComparisonOrLogicalOp(ctx); - const isMultiple = isComparisonOrLogical - ? false - : Boolean(leftResult.value.isMultiple || rightResult.value.isMultiple); - return ok(new TypedValue(null, valueType, isMultiple)); + // Binary operators unwrap arrays to scalar values in SQL translation. + // Keep v1 parity by inferring scalar results for all binary operations. + return ok(new TypedValue(null, valueType, false)); } visitFieldReferenceCurly(ctx: FieldReferenceCurlyContext): Result { @@ -146,19 +141,6 @@ export class FormulaTypeVisitor return ok(new TypedValue(null, returnResult.value.type, returnResult.value.isMultiple)); } - private isComparisonOrLogicalOp(ctx: BinaryOpContext): boolean { - return Boolean( - ctx.PIPE_PIPE() || - ctx.AMP_AMP() || - ctx.EQUAL() || - ctx.BANG_EQUAL() || - ctx.GT() || - ctx.GTE() || - ctx.LT() || - ctx.LTE() - ); - } - private getBinaryOpValueType( ctx: BinaryOpContext, left: TypedValue, diff --git a/packages/v2/core/src/domain/table/Table.spec.ts b/packages/v2/core/src/domain/table/Table.spec.ts index 40a58d96c..e0351e289 100644 --- a/packages/v2/core/src/domain/table/Table.spec.ts +++ b/packages/v2/core/src/domain/table/Table.spec.ts @@ -1,8 +1,9 @@ import { ok } from 'neverthrow'; -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { BaseId } from '../base/BaseId'; import { DbTableName } from './DbTableName'; +import { DbFieldName } from './fields/DbFieldName'; import { FieldDeleted } from './events/FieldDeleted'; import { FieldUpdated } from './events/FieldUpdated'; import { TableCreated } from './events/TableCreated'; @@ -13,6 +14,8 @@ import { FieldId } from './fields/FieldId'; import { FieldName } from './fields/FieldName'; import { CheckboxDefaultValue } from './fields/types/CheckboxDefaultValue'; import { CheckboxField } from './fields/types/CheckboxField'; +import { FieldNotNull } from './fields/types/FieldNotNull'; +import { FieldUnique } from './fields/types/FieldUnique'; import { FormulaExpression } from './fields/types/FormulaExpression'; import { LongTextField } from './fields/types/LongTextField'; import { NumberDefaultValue } from './fields/types/NumberDefaultValue'; @@ -294,6 +297,204 @@ describe('Table', () => { expect(addedEntry.order).toBe(maxOrder + 1); }); + it('rejects adding a field with duplicate dbFieldName', () => { + const baseIdResult = createBaseId('d'); + const tableNameResult = TableName.create('Duplicate DbFieldName'); + const primaryFieldNameResult = FieldName.create('Title'); + const viewNameResult = ViewName.create('Grid'); + const secondFieldNameResult = FieldName.create('Text-1'); + const thirdFieldNameResult = FieldName.create('Text-2'); + const secondFieldIdResult = createFieldId('e'); + const thirdFieldIdResult = createFieldId('f'); + const duplicateDbFieldNameResult = DbFieldName.rehydrate('fld_duplicate_db_field'); + + [ + baseIdResult, + tableNameResult, + primaryFieldNameResult, + viewNameResult, + secondFieldNameResult, + thirdFieldNameResult, + secondFieldIdResult, + thirdFieldIdResult, + duplicateDbFieldNameResult, + ].forEach((result) => result._unsafeUnwrap()); + + const builder = Table.builder() + .withBaseId(baseIdResult._unsafeUnwrap()) + .withName(tableNameResult._unsafeUnwrap()); + builder.field().singleLineText().withName(primaryFieldNameResult._unsafeUnwrap()).done(); + builder.view().grid().withName(viewNameResult._unsafeUnwrap()).done(); + const tableResult = builder.build(); + tableResult._unsafeUnwrap(); + const table = tableResult._unsafeUnwrap(); + + const secondFieldResult = SingleLineTextField.create({ + id: secondFieldIdResult._unsafeUnwrap(), + name: secondFieldNameResult._unsafeUnwrap(), + }).andThen((field) => + field.setDbFieldName(duplicateDbFieldNameResult._unsafeUnwrap()).map(() => field) + ); + secondFieldResult._unsafeUnwrap(); + + const tableAfterSecondFieldResult = table.update((mutator) => + mutator.addField(secondFieldResult._unsafeUnwrap()) + ); + tableAfterSecondFieldResult._unsafeUnwrap(); + + const thirdFieldResult = SingleLineTextField.create({ + id: thirdFieldIdResult._unsafeUnwrap(), + name: thirdFieldNameResult._unsafeUnwrap(), + }).andThen((field) => + field.setDbFieldName(duplicateDbFieldNameResult._unsafeUnwrap()).map(() => field) + ); + thirdFieldResult._unsafeUnwrap(); + + const duplicateResult = tableAfterSecondFieldResult + ._unsafeUnwrap() + .table.update((mutator) => mutator.addField(thirdFieldResult._unsafeUnwrap())); + + expect(duplicateResult.isErr()).toBe(true); + if (duplicateResult.isErr()) { + expect(duplicateResult.error.message).toContain('already exists in this table'); + } + }); + + it('duplicates field and preserves common metadata in mutator flow', () => { + const baseIdResult = createBaseId('m'); + const tableNameResult = TableName.create('Duplicate Metadata'); + const primaryFieldNameResult = FieldName.create('Title'); + const sourceFieldNameResult = FieldName.create('Source'); + const duplicatedFieldIdResult = createFieldId('n'); + const duplicatedFieldNameResult = FieldName.create('Source (copy)'); + + const builder = Table.builder() + .withBaseId(baseIdResult._unsafeUnwrap()) + .withName(tableNameResult._unsafeUnwrap()); + builder + .field() + .singleLineText() + .withName(primaryFieldNameResult._unsafeUnwrap()) + .primary() + .done(); + builder.field().singleLineText().withName(sourceFieldNameResult._unsafeUnwrap()).done(); + builder.view().defaultGrid().done(); + const buildResult = builder.build(); + buildResult._unsafeUnwrap(); + + const table = buildResult._unsafeUnwrap(); + const sourceSpecResult = Field.specs() + .withFieldName(sourceFieldNameResult._unsafeUnwrap()) + .build(); + sourceSpecResult._unsafeUnwrap(); + const [sourceField] = table.getFields(sourceSpecResult._unsafeUnwrap()); + expect(sourceField).toBeDefined(); + if (!sourceField) return; + + sourceField.setDescription('copy me')._unsafeUnwrap(); + sourceField.setAiConfig({ provider: 'openai', prompt: 'metadata copy' })._unsafeUnwrap(); + sourceField.setNotNull(FieldNotNull.required())._unsafeUnwrap(); + sourceField.setUnique(FieldUnique.enabled())._unsafeUnwrap(); + sourceField + .setDbFieldName(DbFieldName.rehydrate('fld_source_duplicate_guard')._unsafeUnwrap()) + ._unsafeUnwrap(); + + const updateResult = table.update((mutator) => + mutator.duplicateField( + sourceField, + duplicatedFieldIdResult._unsafeUnwrap(), + duplicatedFieldNameResult._unsafeUnwrap(), + true + ) + ); + updateResult._unsafeUnwrap(); + + const updatedTable = updateResult._unsafeUnwrap().table; + const duplicatedFieldResult = updatedTable.getField((field) => + field.id().equals(duplicatedFieldIdResult._unsafeUnwrap()) + ); + duplicatedFieldResult._unsafeUnwrap(); + const duplicatedField = duplicatedFieldResult._unsafeUnwrap(); + + expect(duplicatedField.description()).toBe('copy me'); + expect(duplicatedField.aiConfig()).toEqual({ provider: 'openai', prompt: 'metadata copy' }); + expect(duplicatedField.notNull().toBoolean()).toBe(true); + expect(duplicatedField.unique().toBoolean()).toBe(true); + expect(duplicatedField.dbFieldName().isErr()).toBe(true); + }); + + it('rejects duplicate field when duplicated field carries dbFieldName', () => { + const baseIdResult = createBaseId('o'); + const tableNameResult = TableName.create('Duplicate Guard'); + const primaryFieldNameResult = FieldName.create('Title'); + const sourceFieldNameResult = FieldName.create('Source'); + const duplicatedFieldIdResult = createFieldId('p'); + const duplicatedFieldNameResult = FieldName.create('Source (copy)'); + const forcedDbFieldNameResult = DbFieldName.rehydrate('fld_forced_duplicate_db_name'); + + [ + baseIdResult, + tableNameResult, + primaryFieldNameResult, + sourceFieldNameResult, + duplicatedFieldIdResult, + duplicatedFieldNameResult, + forcedDbFieldNameResult, + ].forEach((result) => result._unsafeUnwrap()); + + const builder = Table.builder() + .withBaseId(baseIdResult._unsafeUnwrap()) + .withName(tableNameResult._unsafeUnwrap()); + builder + .field() + .singleLineText() + .withName(primaryFieldNameResult._unsafeUnwrap()) + .primary() + .done(); + builder.field().singleLineText().withName(sourceFieldNameResult._unsafeUnwrap()).done(); + builder.view().defaultGrid().done(); + + const buildResult = builder.build(); + buildResult._unsafeUnwrap(); + const table = buildResult._unsafeUnwrap(); + + const sourceSpecResult = Field.specs() + .withFieldName(sourceFieldNameResult._unsafeUnwrap()) + .build(); + sourceSpecResult._unsafeUnwrap(); + const [sourceField] = table.getFields(sourceSpecResult._unsafeUnwrap()); + expect(sourceField).toBeDefined(); + if (!sourceField) return; + + const originalDuplicate = sourceField.duplicate.bind(sourceField); + const duplicateSpy = vi + .spyOn(sourceField, 'duplicate') + .mockImplementation((params) => + originalDuplicate(params).andThen((duplicatedField) => + duplicatedField + .setDbFieldName(forcedDbFieldNameResult._unsafeUnwrap()) + .map(() => duplicatedField) + ) + ); + + const updateResult = table.update((mutator) => + mutator.duplicateField( + sourceField, + duplicatedFieldIdResult._unsafeUnwrap(), + duplicatedFieldNameResult._unsafeUnwrap(), + true + ) + ); + + duplicateSpy.mockRestore(); + + expect(updateResult.isErr()).toBe(true); + if (updateResult.isErr()) { + expect(updateResult.error.code).toBe('invariant.violation'); + expect(updateResult.error.message).toBe('Duplicated field must not carry dbFieldName'); + } + }); + it('removes a field and updates view column meta', () => { const baseIdResult = createBaseId('x'); const tableNameResult = TableName.create('Remove Field'); diff --git a/packages/v2/core/src/domain/table/Table.ts b/packages/v2/core/src/domain/table/Table.ts index 254b6e0b5..dbf174ac1 100644 --- a/packages/v2/core/src/domain/table/Table.ts +++ b/packages/v2/core/src/domain/table/Table.ts @@ -13,6 +13,7 @@ import { DbTableName } from './DbTableName'; import type { RecordCreateSource } from './events/RecordFieldValuesDTO'; import { TableCreated } from './events/TableCreated'; import { TableDeleted } from './events/TableDeleted'; +import type { DbFieldName } from './fields/DbFieldName'; import type { Field } from './fields/Field'; import type { FieldId } from './fields/FieldId'; import { FieldName } from './fields/FieldName'; @@ -666,6 +667,27 @@ export class Table extends AggregateRoot { return err(domainError.conflict({ message: 'Field names must be unique' })); } + const nextDbFieldNameResult = field.dbFieldName().andThen((dbFieldName) => dbFieldName.value()); + if (nextDbFieldNameResult.isOk()) { + const hasDuplicateDbFieldName = this.fieldsValue.some((existing) => { + const existingDbFieldNameResult = existing + .dbFieldName() + .andThen((dbFieldName) => dbFieldName.value()); + return ( + existingDbFieldNameResult.isOk() && + existingDbFieldNameResult.value === nextDbFieldNameResult.value + ); + }); + + if (hasDuplicateDbFieldName) { + return err( + domainError.conflict({ + message: `Db Field name ${nextDbFieldNameResult.value} already exists in this table`, + }) + ); + } + } + const validationResult = this.validateForeignTables([field], options?.foreignTables); if (validationResult.isErr()) return err(validationResult.error); @@ -688,7 +710,10 @@ export class Table extends AggregateRoot { return Table.rehydrate(props).andThen((nextTable) => { const resolved = field.type().equals(FieldType.formula()) - ? resolveFormulaFields(nextTable) + ? resolveFormulaFields(nextTable, { + ignoreMissingReferenceOnExisting: true, + strictFieldId: field.id(), + }) : ok(undefined); if (resolved.isErr()) return err(resolved.error); return ok(nextTable); @@ -870,6 +895,17 @@ export class Table extends AggregateRoot { return ok(this); } + updateFieldDbFieldName(fieldId: FieldId, dbFieldName: DbFieldName): Result { + const fieldResult = this.getField((field) => field.id().equals(fieldId)); + if (fieldResult.isErr()) return err(fieldResult.error); + + const field = fieldResult.value; + const renameResult = field.renameDbFieldName(dbFieldName); + if (renameResult.isErr()) return err(renameResult.error); + + return ok(this); + } + /** * Replace a field with a new field (for type conversion). * The new field must have the same ID as the old field. @@ -937,7 +973,10 @@ export class Table extends AggregateRoot { return Table.rehydrate(props).andThen((nextTable) => { const resolved = newField.type().equals(FieldType.formula()) - ? resolveFormulaFields(nextTable) + ? resolveFormulaFields(nextTable, { + ignoreMissingReferenceOnExisting: true, + strictFieldId: newField.id(), + }) : ok(undefined); if (resolved.isErr()) return err(resolved.error); return ok(nextTable); diff --git a/packages/v2/core/src/domain/table/TableMutator.ts b/packages/v2/core/src/domain/table/TableMutator.ts index 0c3b1bba1..11aeef9a9 100644 --- a/packages/v2/core/src/domain/table/TableMutator.ts +++ b/packages/v2/core/src/domain/table/TableMutator.ts @@ -6,6 +6,7 @@ import type { ISpecification } from '../shared/specification/ISpecification'; import { SpecBuilder, type SpecBuilderMode } from '../shared/specification/SpecBuilder'; import { Field } from './fields/Field'; import type { FieldId } from './fields/FieldId'; +import type { FieldName } from './fields/FieldName'; import { isForeignTableRelatedField, validateForeignTablesForFields, @@ -21,6 +22,8 @@ import { TableUpdateViewColumnMetaSpec } from './specs/TableUpdateViewColumnMeta import { TableEventGeneratingSpecVisitor } from './specs/visitors/TableEventGeneratingSpecVisitor'; import type { Table } from './Table'; import type { TableName } from './TableName'; +import { ViewColumnMeta } from './views/ViewColumnMeta'; +import type { ViewId } from './views/ViewId'; class TableMutateSpecBuilder extends SpecBuilder { private constructor(private currentTable: Table) { @@ -46,7 +49,13 @@ class TableMutateSpecBuilder extends SpecBuilder } + options?: { + foreignTables?: ReadonlyArray; + viewOrder?: { + viewId: ViewId; + order: number; + }; + } ): TableMutateSpecBuilder { const nextTableResult = this.currentTable.addField(field, options); if (nextTableResult.isErr()) { @@ -64,10 +73,48 @@ class TableMutateSpecBuilder extends SpecBuilder { + if (!options?.viewOrder) { + return TableUpdateViewColumnMetaSpec.fromTableWithFieldId( + nextTableResult.value, + field.id() + ); + } + + const viewResult = nextTableResult.value.getView(options.viewOrder.viewId); + if (viewResult.isErr()) { + return err(viewResult.error); + } + + const columnMetaResult = viewResult.value.columnMeta(); + if (columnMetaResult.isErr()) { + return err(columnMetaResult.error); + } + + const fieldId = field.id(); + const fieldIdStr = fieldId.toString(); + const currentMeta = columnMetaResult.value.toDto(); + const nextMetaResult = ViewColumnMeta.create({ + ...currentMeta, + [fieldIdStr]: { + ...(currentMeta[fieldIdStr] ?? {}), + order: options.viewOrder.order, + }, + }); + if (nextMetaResult.isErr()) { + return err(nextMetaResult.error); + } + + return ok( + TableUpdateViewColumnMetaSpec.create([ + { + viewId: options.viewOrder.viewId, + fieldId, + columnMeta: nextMetaResult.value, + }, + ]) + ); + })(); if (viewSpecResult.isErr()) { this.recordError(viewSpecResult.error); return this; @@ -129,9 +176,52 @@ class TableMutateSpecBuilder extends SpecBuilder }): TableMutator { + addField( + field: Field, + options?: { + foreignTables?: ReadonlyArray
; + viewOrder?: { + viewId: ViewId; + order: number; + }; + } + ): TableMutator { this.builder.addField(field, options); this.hasUpdates = true; return this; @@ -296,8 +399,20 @@ export class TableMutator { return this; } - duplicateField(sourceField: Field, newField: Field, includeRecordValues: boolean): TableMutator { - this.builder.duplicateField(sourceField, newField, includeRecordValues); + duplicateField( + sourceField: Field, + newFieldId: FieldId, + newFieldName: FieldName, + includeRecordValues: boolean, + options?: { targetViewId?: ViewId } + ): TableMutator { + this.builder.duplicateField( + sourceField, + newFieldId, + newFieldName, + includeRecordValues, + options + ); this.hasUpdates = true; return this; } diff --git a/packages/v2/core/src/domain/table/events/FieldCreated.ts b/packages/v2/core/src/domain/table/events/FieldCreated.ts index 2e700a647..c6732e2d6 100644 --- a/packages/v2/core/src/domain/table/events/FieldCreated.ts +++ b/packages/v2/core/src/domain/table/events/FieldCreated.ts @@ -12,12 +12,18 @@ export class FieldCreated extends AbstractTableUpdatedEvent { private constructor( tableId: TableId, baseId: BaseId, - readonly fieldId: FieldId + readonly fieldId: FieldId, + readonly viewOrders?: Readonly> ) { super(tableId, baseId); } - static create(params: { tableId: TableId; baseId: BaseId; fieldId: FieldId }): FieldCreated { - return new FieldCreated(params.tableId, params.baseId, params.fieldId); + static create(params: { + tableId: TableId; + baseId: BaseId; + fieldId: FieldId; + viewOrders?: Readonly>; + }): FieldCreated { + return new FieldCreated(params.tableId, params.baseId, params.fieldId, params.viewOrders); } } diff --git a/packages/v2/core/src/domain/table/fields/Field.ts b/packages/v2/core/src/domain/table/fields/Field.ts index 22d0fd0e6..8a7baaef0 100644 --- a/packages/v2/core/src/domain/table/fields/Field.ts +++ b/packages/v2/core/src/domain/table/fields/Field.ts @@ -35,7 +35,8 @@ export abstract class Field extends Entity { dbFieldName?: DbFieldName, dependencies: ReadonlyArray = [], computed?: FieldComputed, - description: string | null = null + description: string | null = null, + aiConfig?: unknown | null ) { super(id); this.dbFieldNameValue = dbFieldName ?? DbFieldName.empty(); @@ -43,6 +44,7 @@ export abstract class Field extends Entity { this.dependenciesValue = [...dependencies]; this.computedValue = computed ?? FieldComputed.manual(); this.descriptionValue = description; + this.aiConfigValue = aiConfig; this.hasErrorValue = FieldHasError.ok(); this.notNullValue = FieldNotNull.optional(); this.uniqueValue = FieldUnique.disabled(); @@ -54,6 +56,7 @@ export abstract class Field extends Entity { private dependentsValue: ReadonlyArray | undefined; private readonly computedValue: FieldComputed; private descriptionValue: string | null; + private aiConfigValue: unknown | null | undefined; private hasErrorValue: FieldHasError; private notNullValue: FieldNotNull; private uniqueValue: FieldUnique; @@ -78,6 +81,15 @@ export abstract class Field extends Entity { return this.descriptionValue; } + aiConfig(): unknown | null | undefined { + return this.aiConfigValue; + } + + setAiConfig(aiConfig: unknown | null | undefined): Result { + this.aiConfigValue = aiConfig; + return ok(undefined); + } + setDescription(description: string | null): Result { if (this.descriptionValue === description) return ok(undefined); this.descriptionValue = description; @@ -141,6 +153,19 @@ export abstract class Field extends Entity { return ok(undefined); } + renameDbFieldName(dbFieldName: DbFieldName): Result { + const nextValue = dbFieldName.value(); + if (nextValue.isErr()) return err(nextValue.error); + + const currentValue = this.dbFieldNameValue.value(); + if (currentValue.isErr()) { + return err(domainError.invariant({ message: 'DbFieldName not set' })); + } + + this.dbFieldNameValue = dbFieldName; + return ok(undefined); + } + dbFieldType(): Result { const valueResult = this.dbFieldTypeValue.value(); if (valueResult.isErr()) return err(valueResult.error); diff --git a/packages/v2/core/src/domain/table/fields/FieldFactory.ts b/packages/v2/core/src/domain/table/fields/FieldFactory.ts index f3ed27411..f5e39edba 100644 --- a/packages/v2/core/src/domain/table/fields/FieldFactory.ts +++ b/packages/v2/core/src/domain/table/fields/FieldFactory.ts @@ -175,6 +175,8 @@ export const createLookupFieldPending = (params: { name: FieldName; lookupOptions: LookupOptions; isMultipleCellValue?: boolean; + innerOptionsPatch?: Readonly>; + legacyMultiplicityDerivation?: boolean; dependencies?: ReadonlyArray; notNull?: FieldNotNull; unique?: FieldUnique; @@ -366,6 +368,7 @@ export const createConditionalLookupField = (params: { conditionalLookupOptions: ConditionalLookupOptions; dependencies?: ReadonlyArray; isMultipleCellValue?: boolean; + innerOptionsPatch?: Readonly>; notNull?: FieldNotNull; unique?: FieldUnique; }): Result => @@ -376,6 +379,7 @@ export const createConditionalLookupFieldPending = (params: { name: FieldName; conditionalLookupOptions: ConditionalLookupOptions; dependencies?: ReadonlyArray; + innerOptionsPatch?: Readonly>; notNull?: FieldNotNull; unique?: FieldUnique; }): Result => diff --git a/packages/v2/core/src/domain/table/fields/types/ButtonField.ts b/packages/v2/core/src/domain/table/fields/types/ButtonField.ts index 816c08a1f..91cad4b7b 100644 --- a/packages/v2/core/src/domain/table/fields/types/ButtonField.ts +++ b/packages/v2/core/src/domain/table/fields/types/ButtonField.ts @@ -77,7 +77,7 @@ export class ButtonField extends Field { color: this.color(), maxCount: this.maxCount(), resetCount: this.resetCount(), - workflow: this.workflow(), + workflow: undefined, }); } diff --git a/packages/v2/core/src/domain/table/fields/types/ConditionalLookupField.spec.ts b/packages/v2/core/src/domain/table/fields/types/ConditionalLookupField.spec.ts index db23f059c..58fb8b8fb 100644 --- a/packages/v2/core/src/domain/table/fields/types/ConditionalLookupField.spec.ts +++ b/packages/v2/core/src/domain/table/fields/types/ConditionalLookupField.spec.ts @@ -40,6 +40,50 @@ const createConditionalLookupField = (statusFieldId: FieldId) => { }; describe('ConditionalLookupField.onDependencyUpdated', () => { + it('preserves inner options patch when duplicated', () => { + const statusFieldId = createFieldId('z'); + const field = ConditionalLookupField.create({ + id: createFieldId('y'), + name: FieldName.create('Conditional Lookup')._unsafeUnwrap(), + innerField: SingleLineTextField.create({ + id: createFieldId('x'), + name: FieldName.create('Title')._unsafeUnwrap(), + })._unsafeUnwrap(), + conditionalLookupOptions: ConditionalLookupOptions.create({ + foreignTableId: createTableId('w').toString(), + lookupFieldId: createFieldId('v').toString(), + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: statusFieldId.toString(), operator: 'is', value: 'Active' }], + }, + }, + })._unsafeUnwrap(), + innerOptionsPatch: { + formatting: { + type: 'currency', + precision: 1, + symbol: '¥', + }, + }, + })._unsafeUnwrap(); + + const duplicated = field + .duplicate({ + newId: createFieldId('u'), + newName: FieldName.create('Conditional Lookup Copy')._unsafeUnwrap(), + }) + ._unsafeUnwrap() as ConditionalLookupField; + + expect(duplicated.innerOptionsPatch()).toEqual({ + formatting: { + type: 'currency', + precision: 1, + symbol: '¥', + }, + }); + }); + it('marks hasError when referenced field is type-converted', () => { const statusFieldId = createFieldId('a'); const conditionalLookup = createConditionalLookupField(statusFieldId); diff --git a/packages/v2/core/src/domain/table/fields/types/ConditionalLookupField.ts b/packages/v2/core/src/domain/table/fields/types/ConditionalLookupField.ts index dd9796fdf..63f4af387 100644 --- a/packages/v2/core/src/domain/table/fields/types/ConditionalLookupField.ts +++ b/packages/v2/core/src/domain/table/fields/types/ConditionalLookupField.ts @@ -62,6 +62,7 @@ export class ConditionalLookupField implements ForeignTableRelatedField, OnTeableFieldUpdated { private innerFieldValue: Field | undefined; + private readonly innerOptionsPatchValue: Readonly> | undefined; /** * Override for isMultipleCellValue. When set, this value is used instead of * defaulting to multiple. This is important for compatibility with v1. @@ -75,7 +76,8 @@ export class ConditionalLookupField private readonly conditionalLookupOptionsValue: ConditionalLookupOptions, dbFieldName?: DbFieldName, dependencies?: ReadonlyArray, - isMultipleCellValue?: boolean + isMultipleCellValue?: boolean, + innerOptionsPatch?: Readonly> ) { super( id, @@ -87,6 +89,7 @@ export class ConditionalLookupField ); this.innerFieldValue = innerField; this.isMultipleCellValueOverride = isMultipleCellValue; + this.innerOptionsPatchValue = innerOptionsPatch ? { ...innerOptionsPatch } : undefined; } /** @@ -100,6 +103,7 @@ export class ConditionalLookupField dbFieldName?: DbFieldName; dependencies?: ReadonlyArray; isMultipleCellValue?: boolean; + innerOptionsPatch?: Readonly>; }): Result { return ok( new ConditionalLookupField( @@ -109,7 +113,8 @@ export class ConditionalLookupField params.conditionalLookupOptions, params.dbFieldName, params.dependencies, - params.isMultipleCellValue + params.isMultipleCellValue, + params.innerOptionsPatch ) ); } @@ -125,6 +130,7 @@ export class ConditionalLookupField dbFieldName?: DbFieldName; dependencies?: ReadonlyArray; isMultipleCellValue?: boolean; + innerOptionsPatch?: Readonly>; }): Result { return ok( new ConditionalLookupField( @@ -134,7 +140,8 @@ export class ConditionalLookupField params.conditionalLookupOptions, params.dbFieldName, params.dependencies, - params.isMultipleCellValue + params.isMultipleCellValue, + params.innerOptionsPatch ) ); } @@ -150,6 +157,7 @@ export class ConditionalLookupField dbFieldName?: DbFieldName; dependencies?: ReadonlyArray; isMultipleCellValue?: boolean; + innerOptionsPatch?: Readonly>; }): Result { return ConditionalLookupField.create(params); } @@ -195,6 +203,10 @@ export class ConditionalLookupField return this.conditionalLookupOptionsValue.toDto(); } + innerOptionsPatch(): Readonly> | undefined { + return this.innerOptionsPatchValue; + } + /** * The ID of the field being looked up in the foreign table. */ @@ -340,6 +352,7 @@ export class ConditionalLookupField conditionalLookupOptions: this.conditionalLookupOptions(), isMultipleCellValue, dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, }); } @@ -349,6 +362,7 @@ export class ConditionalLookupField conditionalLookupOptions: this.conditionalLookupOptions(), isMultipleCellValue, dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, }); } @@ -436,6 +450,7 @@ export class ConditionalLookupField conditionalLookupOptions: nextOptionsResult.value, isMultipleCellValue: multiplicityResult.value.isMultiple(), dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, }) ) .orElse(() => @@ -445,6 +460,7 @@ export class ConditionalLookupField conditionalLookupOptions: nextOptionsResult.value, isMultipleCellValue: multiplicityResult.value.isMultiple(), dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, }) ); if (nextFieldResult.isErr()) { diff --git a/packages/v2/core/src/domain/table/fields/types/ConditionalRollupField.ts b/packages/v2/core/src/domain/table/fields/types/ConditionalRollupField.ts index 7c62ff1c4..a98624446 100644 --- a/packages/v2/core/src/domain/table/fields/types/ConditionalRollupField.ts +++ b/packages/v2/core/src/domain/table/fields/types/ConditionalRollupField.ts @@ -14,13 +14,6 @@ import type { FieldDuplicateParams } from '../Field'; import type { FieldId } from '../FieldId'; import type { FieldName } from '../FieldName'; import { FieldType } from '../FieldType'; -import type { - ForeignTableRelatedField, - ForeignTableValidationContext, -} from '../ForeignTableRelatedField'; -import type { FieldUpdateContext, OnTeableFieldUpdated } from '../OnTeableFieldUpdated'; -import { FieldValueTypeVisitor } from '../visitors/FieldValueTypeVisitor'; -import type { IFieldVisitor } from '../visitors/IFieldVisitor'; import { buildFieldFilterSyncPlan, hasFieldReferenceInFilter, @@ -28,7 +21,14 @@ import { isEquivalentFilter, syncFilterByFieldChanges, } from '../filter-sync'; -import type { CellValueMultiplicity } from './CellValueMultiplicity'; +import type { + ForeignTableRelatedField, + ForeignTableValidationContext, +} from '../ForeignTableRelatedField'; +import type { FieldUpdateContext, OnTeableFieldUpdated } from '../OnTeableFieldUpdated'; +import { FieldValueTypeVisitor } from '../visitors/FieldValueTypeVisitor'; +import type { IFieldVisitor } from '../visitors/IFieldVisitor'; +import { CellValueMultiplicity } from './CellValueMultiplicity'; import { CellValueType } from './CellValueType'; import { ConditionalRollupConfig, @@ -37,6 +37,7 @@ import { import type { DateTimeFormatting } from './DateTimeFormatting'; import { DateTimeFormatting as DateTimeFormattingValue } from './DateTimeFormatting'; import { FieldComputed } from './FieldComputed'; +import { FieldHasError } from './FieldHasError'; import { NumberFormatting as NumberFormattingValue } from './NumberFormatting'; import type { NumberFormatting } from './NumberFormatting'; import { NumberShowAs as NumberShowAsValue } from './NumberShowAs'; @@ -319,16 +320,24 @@ export class ConditionalRollupField } cellValueType(): Result { - if (!this.cellValueTypeValue) + if (!this.cellValueTypeValue) { + if (this.hasError().isError()) { + return ok(CellValueType.string()); + } return err( domainError.invariant({ message: 'ConditionalRollupField cell value type not set' }) ); + } return ok(this.cellValueTypeValue); } isMultipleCellValue(): Result { - if (!this.isMultipleCellValueValue) + if (!this.isMultipleCellValueValue) { + if (this.hasError().isError()) { + return ok(CellValueMultiplicity.single()); + } return err(domainError.invariant({ message: 'ConditionalRollupField multiplicity not set' })); + } return ok(this.isMultipleCellValueValue); } @@ -405,7 +414,9 @@ export class ConditionalRollupField cellValueType: valuesTypeResult.value.cellValueType, isMultipleCellValue: valuesTypeResult.value.isMultipleCellValue, }); - if (resolveResult.isErr()) return err(resolveResult.error); + if (resolveResult.isErr()) { + this.setHasError(FieldHasError.error()); + } } // Dependencies include host fields referenced by condition value expressions. diff --git a/packages/v2/core/src/domain/table/fields/types/FieldCondition.ts b/packages/v2/core/src/domain/table/fields/types/FieldCondition.ts index a5e3a1811..a56753f50 100644 --- a/packages/v2/core/src/domain/table/fields/types/FieldCondition.ts +++ b/packages/v2/core/src/domain/table/fields/types/FieldCondition.ts @@ -503,15 +503,28 @@ export class FieldCondition extends ValueObject { ); } - const fieldIdResult = FieldId.create(filterItemEntry.fieldId); + const isFieldRefObject = + typeof filterItemEntry.value === 'object' && + filterItemEntry.value !== null && + 'type' in filterItemEntry.value && + (filterItemEntry.value as { type?: string }).type === 'field' && + 'fieldId' in filterItemEntry.value; + const isSelfTableReference = + isFieldRefObject && hostTable !== undefined && hostTable.id().equals(table.id()); + const effectiveFieldIdValue = + isSelfTableReference && isFieldRefObject + ? (filterItemEntry.value as { fieldId: string }).fieldId + : filterItemEntry.fieldId; + + const fieldIdResult = FieldId.create(effectiveFieldIdValue); if (fieldIdResult.isErr()) return err(fieldIdResult.error); const field = fields.find((f) => f.id().equals(fieldIdResult.value)); if (!field) { return err( domainError.notFound({ code: 'field.condition.field_not_found', - message: `Field not found: ${filterItemEntry.fieldId}`, - details: { fieldId: filterItemEntry.fieldId }, + message: `Field not found: ${effectiveFieldIdValue}`, + details: { fieldId: effectiveFieldIdValue }, }) ); } @@ -520,18 +533,12 @@ export class FieldCondition extends ValueObject { // `value: null` is commonly used by v1-style filters for operators that don't require a value // (e.g. `isEmpty`, `isNotEmpty`). Treat null the same as "not provided". if (filterItemEntry.value !== undefined && filterItemEntry.value !== null) { - // Check if value is a field reference object: { type: 'field', fieldId: ... } - const isFieldRefObject = - typeof filterItemEntry.value === 'object' && - filterItemEntry.value !== null && - 'type' in filterItemEntry.value && - (filterItemEntry.value as { type?: string }).type === 'field' && - 'fieldId' in filterItemEntry.value; - if (filterItemEntry.isSymbol || isFieldRefObject) { // Field reference - resolve from host table if provided, otherwise from main table const refFieldIdValue = isFieldRefObject - ? (filterItemEntry.value as { fieldId: string }).fieldId + ? isSelfTableReference + ? filterItemEntry.fieldId + : (filterItemEntry.value as { fieldId: string }).fieldId : String(filterItemEntry.value); const refFieldId = yield* FieldId.create(refFieldIdValue); const refField = hostFields.find((f) => f.id().equals(refFieldId)); diff --git a/packages/v2/core/src/domain/table/fields/types/LinkField.spec.ts b/packages/v2/core/src/domain/table/fields/types/LinkField.spec.ts index 33a80e79a..043eb5fc0 100644 --- a/packages/v2/core/src/domain/table/fields/types/LinkField.spec.ts +++ b/packages/v2/core/src/domain/table/fields/types/LinkField.spec.ts @@ -4,15 +4,15 @@ import { describe, expect, it } from 'vitest'; import { BaseId } from '../../../base/BaseId'; import type { DomainError } from '../../../shared/DomainError'; import { ForeignTable } from '../../ForeignTable'; +import { UpdateLinkConfigSpec } from '../../specs/field-updates/UpdateLinkConfigSpec'; +import { UpdateSingleSelectOptionsSpec } from '../../specs/field-updates/UpdateSingleSelectOptionsSpec'; import { Table } from '../../Table'; import { TableId } from '../../TableId'; import { TableName } from '../../TableName'; -import { DbFieldName } from '../DbFieldName'; import { ViewId } from '../../views/ViewId'; +import { DbFieldName } from '../DbFieldName'; import { FieldId } from '../FieldId'; import { FieldName } from '../FieldName'; -import { UpdateLinkConfigSpec } from '../../specs/field-updates/UpdateLinkConfigSpec'; -import { UpdateSingleSelectOptionsSpec } from '../../specs/field-updates/UpdateSingleSelectOptionsSpec'; import { LinkField } from './LinkField'; import { LinkFieldConfig } from './LinkFieldConfig'; import { LinkFieldMeta } from './LinkFieldMeta'; @@ -437,6 +437,71 @@ describe('LinkField', () => { ).toBe(true); }); + it('ensures symmetricFieldId even when db config already exists', () => { + const baseId = createBaseId('g')._unsafeUnwrap(); + const hostTableId = createTableId('h')._unsafeUnwrap(); + const foreignTableId = createTableId('i')._unsafeUnwrap(); + const lookupFieldId = createFieldId('j')._unsafeUnwrap(); + const linkFieldId = createFieldId('k')._unsafeUnwrap(); + const linkFieldName = FieldName.create('Link')._unsafeUnwrap(); + + const field = LinkFieldConfig.create({ + relationship: LinkRelationship.manyOne().toString(), + foreignTableId: foreignTableId.toString(), + lookupFieldId: lookupFieldId.toString(), + fkHostTableName: `${baseId.toString()}.${hostTableId.toString()}`, + selfKeyName: '__id', + foreignKeyName: `__fk_${linkFieldId.toString()}`, + }) + .andThen((config) => + LinkField.create({ + id: linkFieldId, + name: linkFieldName, + config, + }) + ) + ._unsafeUnwrap(); + + field.ensureDbConfig({ baseId, hostTableId })._unsafeUnwrap(); + + const symmetricFieldId = field.symmetricFieldId(); + expect(symmetricFieldId).toBeDefined(); + expect(symmetricFieldId?.equals(linkFieldId)).toBe(false); + + expect(field.fkHostTableNameString()._unsafeUnwrap()).toBe( + `${baseId.toString()}.${hostTableId.toString()}` + ); + expect(field.selfKeyNameString()._unsafeUnwrap()).toBe('__id'); + expect(field.foreignKeyNameString()._unsafeUnwrap()).toBe(`__fk_${linkFieldId.toString()}`); + }); + + it('normalizes same-base baseId when creating a link field', () => { + const baseId = createBaseId('w')._unsafeUnwrap(); + const hostTableId = createTableId('x')._unsafeUnwrap(); + const foreignTableId = createTableId('y')._unsafeUnwrap(); + const lookupFieldId = createFieldId('z')._unsafeUnwrap(); + const linkFieldId = createFieldId('a')._unsafeUnwrap(); + const linkFieldName = FieldName.create('Link')._unsafeUnwrap(); + + const config = LinkFieldConfig.create({ + baseId: baseId.toString(), + relationship: LinkRelationship.manyOne().toString(), + foreignTableId: foreignTableId.toString(), + lookupFieldId: lookupFieldId.toString(), + })._unsafeUnwrap(); + + const field = LinkField.createNew({ + id: linkFieldId, + name: linkFieldName, + config, + baseId, + hostTableId, + })._unsafeUnwrap(); + + expect(field.baseId()).toBeUndefined(); + expect(field.isCrossBase()).toBe(false); + }); + it('builds symmetric fields and swaps db config', () => { const baseIdResult = createBaseId('1'); const hostTableIdResult = createTableId('2'); @@ -518,6 +583,7 @@ describe('LinkField', () => { expect(symmetric.foreignTableId().equals(hostTableId)).toBe(true); expect(symmetric.lookupFieldId().equals(hostPrimaryId)).toBe(true); expect(symmetric.symmetricFieldId()?.equals(linkFieldId)).toBe(true); + expect(symmetric.baseId()).toBeUndefined(); expect(symmetric.meta()?.hasOrderColumn()).toBe(true); expect(symmetric.name().toString()).toBe('Host'); @@ -527,6 +593,68 @@ describe('LinkField', () => { expect(symmetricForeignKey._unsafeUnwrap()).toBe('__id'); }); + it('sets symmetric baseId to host base for cross-base links', () => { + const hostBaseId = createBaseId('h')._unsafeUnwrap(); + const foreignBaseId = createBaseId('i')._unsafeUnwrap(); + const hostTableId = createTableId('j')._unsafeUnwrap(); + const foreignTableId = createTableId('k')._unsafeUnwrap(); + const hostPrimaryId = createFieldId('l')._unsafeUnwrap(); + const foreignPrimaryId = createFieldId('m')._unsafeUnwrap(); + const linkFieldId = createFieldId('n')._unsafeUnwrap(); + + const hostBuilder = Table.builder() + .withId(hostTableId) + .withBaseId(hostBaseId) + .withName(TableName.create('Cross Host')._unsafeUnwrap()); + hostBuilder + .field() + .singleLineText() + .withId(hostPrimaryId) + .withName(FieldName.create('Host Name')._unsafeUnwrap()) + .primary() + .done(); + hostBuilder.view().defaultGrid().done(); + const hostTable = hostBuilder.build()._unsafeUnwrap(); + + const foreignBuilder = Table.builder() + .withId(foreignTableId) + .withBaseId(foreignBaseId) + .withName(TableName.create('Cross Foreign')._unsafeUnwrap()); + foreignBuilder + .field() + .singleLineText() + .withId(foreignPrimaryId) + .withName(FieldName.create('Foreign Name')._unsafeUnwrap()) + .primary() + .done(); + foreignBuilder.view().defaultGrid().done(); + const foreignTable = ForeignTable.from(foreignBuilder.build()._unsafeUnwrap()); + + const config = LinkFieldConfig.create({ + baseId: foreignBaseId.toString(), + relationship: 'manyOne', + foreignTableId: foreignTableId.toString(), + lookupFieldId: foreignPrimaryId.toString(), + })._unsafeUnwrap(); + + const linkField = LinkField.createNew({ + id: linkFieldId, + name: FieldName.create('Cross Link')._unsafeUnwrap(), + config, + baseId: hostBaseId, + hostTableId, + })._unsafeUnwrap(); + + const symmetric = linkField + .buildSymmetricField({ + foreignTable, + hostTable, + }) + ._unsafeUnwrap(); + + expect(symmetric.baseId()?.equals(hostBaseId)).toBe(true); + }); + it('rejects symmetric build for one-way links', () => { const baseIdResult = createBaseId('7'); const foreignTableIdResult = createTableId('8'); diff --git a/packages/v2/core/src/domain/table/fields/types/LinkField.ts b/packages/v2/core/src/domain/table/fields/types/LinkField.ts index a7a3f52b5..7c0965296 100644 --- a/packages/v2/core/src/domain/table/fields/types/LinkField.ts +++ b/packages/v2/core/src/domain/table/fields/types/LinkField.ts @@ -6,8 +6,8 @@ import { domainError, type DomainError } from '../../../shared/DomainError'; import type { ISpecification } from '../../../shared/specification/ISpecification'; import { DbTableName } from '../../DbTableName'; import { ForeignTable } from '../../ForeignTable'; -import type { ITableSpecVisitor } from '../../specs/ITableSpecVisitor'; import { UpdateLinkConfigSpec } from '../../specs/field-updates/UpdateLinkConfigSpec'; +import type { ITableSpecVisitor } from '../../specs/ITableSpecVisitor'; import type { Table } from '../../Table'; import type { TableId } from '../../TableId'; import type { ViewId } from '../../views/ViewId'; @@ -17,12 +17,6 @@ import type { FieldDuplicateParams } from '../Field'; import { FieldId } from '../FieldId'; import { FieldName } from '../FieldName'; import { FieldType } from '../FieldType'; -import type { - ForeignTableRelatedField, - ForeignTableValidationContext, -} from '../ForeignTableRelatedField'; -import type { FieldUpdateContext, OnTeableFieldUpdated } from '../OnTeableFieldUpdated'; -import type { IFieldVisitor } from '../visitors/IFieldVisitor'; import { buildFieldFilterSyncPlan, hasFieldFilterSyncPlanChanges, @@ -30,6 +24,12 @@ import { isEquivalentFilter, syncFilterByFieldChanges, } from '../filter-sync'; +import type { + ForeignTableRelatedField, + ForeignTableValidationContext, +} from '../ForeignTableRelatedField'; +import type { FieldUpdateContext, OnTeableFieldUpdated } from '../OnTeableFieldUpdated'; +import type { IFieldVisitor } from '../visitors/IFieldVisitor'; import { LinkFieldConfig, type LinkFieldConfigValue, @@ -69,16 +69,18 @@ export class LinkField extends Field implements ForeignTableRelatedField, OnTeab ? ok(params.meta) : LinkField.defaultMetaForConfig(params.config); - return metaResult.andThen((meta) => - LinkField.create({ - id: params.id, - name: params.name, - config: params.config, - meta, - }).andThen((field) => - field - .ensureDbConfig({ baseId: params.baseId, hostTableId: params.hostTableId }) - .map(() => field) + return LinkField.normalizeCrossBaseConfig(params.config, params.baseId).andThen((config) => + metaResult.andThen((meta) => + LinkField.create({ + id: params.id, + name: params.name, + config, + meta, + }).andThen((field) => + field + .ensureDbConfig({ baseId: params.baseId, hostTableId: params.hostTableId }) + .map(() => field) + ) ) ); } @@ -256,7 +258,11 @@ export class LinkField extends Field implements ForeignTableRelatedField, OnTeab ? ok(this.symmetricFieldId()!) : FieldId.generate(); - const baseId = this.isCrossBase() ? hostTable.baseId().toString() : undefined; + const baseId = this.baseId() + ? this.baseId()!.equals(hostTable.baseId()) + ? undefined + : hostTable.baseId().toString() + : undefined; const lookupFieldId = hostTable.primaryFieldId().toString(); const symmetricDbConfigResult: Result = @@ -360,8 +366,6 @@ export class LinkField extends Field implements ForeignTableRelatedField, OnTeab } ensureDbConfig(params: { baseId: BaseId; hostTableId: TableId }): Result { - if (this.configValue.hasDbConfig()) return ok(undefined); - const symmetricFieldIdResult = (() => { if (this.isOneWay()) return ok(this.symmetricFieldId()); if (this.symmetricFieldId()) return ok(this.symmetricFieldId()); @@ -371,6 +375,9 @@ export class LinkField extends Field implements ForeignTableRelatedField, OnTeab })(); if (symmetricFieldIdResult.isErr()) return err(symmetricFieldIdResult.error); + + if (this.configValue.hasDbConfig()) return ok(undefined); + const symmetricFieldId = symmetricFieldIdResult.value; return this.resolveFkHostTableName({ @@ -430,6 +437,47 @@ export class LinkField extends Field implements ForeignTableRelatedField, OnTeab return DbTableName.rehydrate(`${baseId.toString()}.junction_${suffix}`); } + private static normalizeCrossBaseConfig( + config: LinkFieldConfig, + hostBaseId: BaseId + ): Result { + const configBaseId = config.baseId(); + if (!configBaseId || !configBaseId.equals(hostBaseId)) { + return ok(config); + } + + const baseOptions = { + relationship: config.relationship().toString(), + foreignTableId: config.foreignTableId().toString(), + lookupFieldId: config.lookupFieldId().toString(), + isOneWay: config.isOneWay(), + symmetricFieldId: config.symmetricFieldId()?.toString(), + filterByViewId: config.filterByViewId() === null ? null : config.filterByViewId()?.toString(), + visibleFieldIds: + config.visibleFieldIds() === null + ? null + : config.visibleFieldIds()?.map((fieldId) => fieldId.toString()), + filter: config.filter() ?? undefined, + }; + + if (!config.hasDbConfig()) { + return LinkFieldConfig.create(baseOptions); + } + + return config.fkHostTableNameString().andThen((fkHostTableName) => + config.selfKeyNameString().andThen((selfKeyName) => + config.foreignKeyNameString().andThen((foreignKeyName) => + LinkFieldConfig.create({ + ...baseOptions, + fkHostTableName, + selfKeyName, + foreignKeyName, + }) + ) + ) + ); + } + private static defaultMetaForConfig( config: LinkFieldConfig ): Result { diff --git a/packages/v2/core/src/domain/table/fields/types/LookupField.spec.ts b/packages/v2/core/src/domain/table/fields/types/LookupField.spec.ts index cbb6290ca..9db1e1787 100644 --- a/packages/v2/core/src/domain/table/fields/types/LookupField.spec.ts +++ b/packages/v2/core/src/domain/table/fields/types/LookupField.spec.ts @@ -822,6 +822,227 @@ describe('LookupField', () => { expect(validationResult.isOk()).toBe(true); }); + it('keeps v2 default multiplicity for manyOne lookup without legacy derivation', () => { + const baseId = createBaseId('r')._unsafeUnwrap(); + const hostTableId = createTableId('s')._unsafeUnwrap(); + const foreignTableId = createTableId('t')._unsafeUnwrap(); + const hostPrimaryId = createFieldId('u')._unsafeUnwrap(); + const foreignPrimaryId = createFieldId('v')._unsafeUnwrap(); + const linkFieldId = createFieldId('w')._unsafeUnwrap(); + const lookupFieldId = createFieldId('x')._unsafeUnwrap(); + + const foreignTable = Table.builder() + .withId(foreignTableId) + .withBaseId(baseId) + .withName(TableName.create('Foreign')._unsafeUnwrap()) + .field() + .singleLineText() + .withId(foreignPrimaryId) + .withName(FieldName.create('Foreign Name')._unsafeUnwrap()) + .primary() + .done() + .view() + .defaultGrid() + .done() + .build() + ._unsafeUnwrap(); + + const linkConfig = LinkFieldConfig.create({ + relationship: LinkRelationship.manyOne().toString(), + foreignTableId: foreignTableId.toString(), + lookupFieldId: foreignPrimaryId.toString(), + })._unsafeUnwrap(); + + const hostBuilder = Table.builder() + .withId(hostTableId) + .withBaseId(baseId) + .withName(TableName.create('Host')._unsafeUnwrap()); + hostBuilder + .field() + .singleLineText() + .withId(hostPrimaryId) + .withName(FieldName.create('Host Name')._unsafeUnwrap()) + .primary() + .done(); + hostBuilder + .field() + .link() + .withId(linkFieldId) + .withName(FieldName.create('Link')._unsafeUnwrap()) + .withConfig(linkConfig) + .done(); + hostBuilder.view().defaultGrid().done(); + const hostTable = hostBuilder.build()._unsafeUnwrap(); + + const lookupField = LookupField.createPending({ + id: lookupFieldId, + name: FieldName.create('Lookup')._unsafeUnwrap(), + lookupOptions: LookupOptions.create({ + linkFieldId: linkFieldId.toString(), + foreignTableId: foreignTableId.toString(), + lookupFieldId: foreignPrimaryId.toString(), + })._unsafeUnwrap(), + })._unsafeUnwrap(); + + expect(lookupField.isMultipleCellValue()._unsafeUnwrap().isMultiple()).toBe(true); + + const validationResult = lookupField.validateForeignTables({ + hostTable, + foreignTables: [foreignTable], + }); + expect(validationResult.isOk()).toBe(true); + expect(lookupField.isMultipleCellValue()._unsafeUnwrap().isMultiple()).toBe(true); + }); + + it('derives single multiplicity for manyOne lookup to single-value target in legacy mode', () => { + const baseId = createBaseId('g')._unsafeUnwrap(); + const hostTableId = createTableId('h')._unsafeUnwrap(); + const foreignTableId = createTableId('i')._unsafeUnwrap(); + const hostPrimaryId = createFieldId('j')._unsafeUnwrap(); + const foreignPrimaryId = createFieldId('k')._unsafeUnwrap(); + const linkFieldId = createFieldId('l')._unsafeUnwrap(); + const lookupFieldId = createFieldId('m')._unsafeUnwrap(); + + const foreignTable = Table.builder() + .withId(foreignTableId) + .withBaseId(baseId) + .withName(TableName.create('Foreign Legacy')._unsafeUnwrap()) + .field() + .singleLineText() + .withId(foreignPrimaryId) + .withName(FieldName.create('Foreign Name')._unsafeUnwrap()) + .primary() + .done() + .view() + .defaultGrid() + .done() + .build() + ._unsafeUnwrap(); + + const linkConfig = LinkFieldConfig.create({ + relationship: LinkRelationship.manyOne().toString(), + foreignTableId: foreignTableId.toString(), + lookupFieldId: foreignPrimaryId.toString(), + })._unsafeUnwrap(); + + const hostBuilder = Table.builder() + .withId(hostTableId) + .withBaseId(baseId) + .withName(TableName.create('Host Legacy')._unsafeUnwrap()); + hostBuilder + .field() + .singleLineText() + .withId(hostPrimaryId) + .withName(FieldName.create('Host Name')._unsafeUnwrap()) + .primary() + .done(); + hostBuilder + .field() + .link() + .withId(linkFieldId) + .withName(FieldName.create('Link')._unsafeUnwrap()) + .withConfig(linkConfig) + .done(); + hostBuilder.view().defaultGrid().done(); + const hostTable = hostBuilder.build()._unsafeUnwrap(); + + const lookupField = LookupField.createPending({ + id: lookupFieldId, + name: FieldName.create('Lookup Legacy')._unsafeUnwrap(), + lookupOptions: LookupOptions.create({ + linkFieldId: linkFieldId.toString(), + foreignTableId: foreignTableId.toString(), + lookupFieldId: foreignPrimaryId.toString(), + })._unsafeUnwrap(), + legacyMultiplicityDerivation: true, + })._unsafeUnwrap(); + + const validationResult = lookupField.validateForeignTables({ + hostTable, + foreignTables: [foreignTable], + }); + expect(validationResult.isOk()).toBe(true); + expect(lookupField.isMultipleCellValue()._unsafeUnwrap().isMultiple()).toBe(false); + }); + + it('derives multiple multiplicity when lookup target is multi-value on manyOne link in legacy mode', () => { + const baseId = createBaseId('y')._unsafeUnwrap(); + const hostTableId = createTableId('z')._unsafeUnwrap(); + const foreignTableId = createTableId('a')._unsafeUnwrap(); + const hostPrimaryId = createFieldId('b')._unsafeUnwrap(); + const foreignPrimaryId = createFieldId('c')._unsafeUnwrap(); + const foreignMultiFieldId = createFieldId('d')._unsafeUnwrap(); + const linkFieldId = createFieldId('e')._unsafeUnwrap(); + const lookupFieldId = createFieldId('f')._unsafeUnwrap(); + const option = SelectOption.create({ name: 'Done', color: 'blue' })._unsafeUnwrap(); + + const foreignBuilder = Table.builder() + .withId(foreignTableId) + .withBaseId(baseId) + .withName(TableName.create('Foreign')._unsafeUnwrap()); + foreignBuilder + .field() + .singleLineText() + .withId(foreignPrimaryId) + .withName(FieldName.create('Foreign Name')._unsafeUnwrap()) + .primary() + .done(); + foreignBuilder + .field() + .multipleSelect() + .withId(foreignMultiFieldId) + .withName(FieldName.create('Tags')._unsafeUnwrap()) + .withOptions([option]) + .done(); + foreignBuilder.view().defaultGrid().done(); + const foreignTable = foreignBuilder.build()._unsafeUnwrap(); + + const linkConfig = LinkFieldConfig.create({ + relationship: LinkRelationship.manyOne().toString(), + foreignTableId: foreignTableId.toString(), + lookupFieldId: foreignPrimaryId.toString(), + })._unsafeUnwrap(); + + const hostBuilder = Table.builder() + .withId(hostTableId) + .withBaseId(baseId) + .withName(TableName.create('Host')._unsafeUnwrap()); + hostBuilder + .field() + .singleLineText() + .withId(hostPrimaryId) + .withName(FieldName.create('Host Name')._unsafeUnwrap()) + .primary() + .done(); + hostBuilder + .field() + .link() + .withId(linkFieldId) + .withName(FieldName.create('Link')._unsafeUnwrap()) + .withConfig(linkConfig) + .done(); + hostBuilder.view().defaultGrid().done(); + const hostTable = hostBuilder.build()._unsafeUnwrap(); + + const lookupField = LookupField.createPending({ + id: lookupFieldId, + name: FieldName.create('Lookup Tags')._unsafeUnwrap(), + lookupOptions: LookupOptions.create({ + linkFieldId: linkFieldId.toString(), + foreignTableId: foreignTableId.toString(), + lookupFieldId: foreignMultiFieldId.toString(), + })._unsafeUnwrap(), + legacyMultiplicityDerivation: true, + })._unsafeUnwrap(); + + const validationResult = lookupField.validateForeignTables({ + hostTable, + foreignTables: [foreignTable], + }); + expect(validationResult.isOk()).toBe(true); + expect(lookupField.isMultipleCellValue()._unsafeUnwrap().isMultiple()).toBe(true); + }); + it('rejects when link field is not found in host table', () => { const baseIdResult = createBaseId('i'); const hostTableIdResult = createTableId('j'); diff --git a/packages/v2/core/src/domain/table/fields/types/LookupField.ts b/packages/v2/core/src/domain/table/fields/types/LookupField.ts index 9de13bfaa..00bb0b804 100644 --- a/packages/v2/core/src/domain/table/fields/types/LookupField.ts +++ b/packages/v2/core/src/domain/table/fields/types/LookupField.ts @@ -53,6 +53,8 @@ import { LookupOptions, type LookupOptionsValue } from './LookupOptions'; */ export class LookupField extends Field implements ForeignTableRelatedField, OnTeableFieldUpdated { private innerFieldValue: Field | undefined; + private readonly innerOptionsPatchValue: Readonly> | undefined; + private readonly legacyMultiplicityDerivationEnabled: boolean; /** * Override for isMultipleCellValue. When set, this value is used instead of * defaulting to multiple. This is important for compatibility with v1 where @@ -61,17 +63,6 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe */ private isMultipleCellValueOverride: boolean | undefined; - private static fallbackDbFieldName(name: string): string { - let normalized = name.replace(/\W+/g, '_').replace(/^_+|_+$/g, ''); - if (!normalized) { - normalized = 'unnamed'; - } - if (!/^[a-z]/i.test(normalized)) { - normalized = `t${normalized}`; - } - return normalized.slice(0, 40); - } - private constructor( id: FieldId, name: FieldName, @@ -79,11 +70,15 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe private readonly lookupOptionsValue: LookupOptions, dbFieldName?: DbFieldName, dependencies?: ReadonlyArray, - isMultipleCellValue?: boolean + isMultipleCellValue?: boolean, + innerOptionsPatch?: Readonly>, + legacyMultiplicityDerivation?: boolean ) { super(id, name, FieldType.lookup(), dbFieldName, dependencies ?? [], FieldComputed.computed()); this.innerFieldValue = innerField; this.isMultipleCellValueOverride = isMultipleCellValue; + this.innerOptionsPatchValue = innerOptionsPatch ? { ...innerOptionsPatch } : undefined; + this.legacyMultiplicityDerivationEnabled = legacyMultiplicityDerivation === true; } static create(params: { @@ -94,6 +89,8 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe dbFieldName?: DbFieldName; dependencies?: ReadonlyArray; isMultipleCellValue?: boolean; + innerOptionsPatch?: Readonly>; + legacyMultiplicityDerivation?: boolean; }): Result { // Nested lookups are supported - inner field can be another LookupField // This enables lookups across 3+ tables (e.g., Table A -> Table B -> Table C) @@ -105,7 +102,9 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe params.lookupOptions, params.dbFieldName, params.dependencies ?? [params.lookupOptions.linkFieldId()], - params.isMultipleCellValue + params.isMultipleCellValue, + params.innerOptionsPatch, + params.legacyMultiplicityDerivation ) ); } @@ -121,6 +120,8 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe dbFieldName?: DbFieldName; dependencies?: ReadonlyArray; isMultipleCellValue?: boolean; + innerOptionsPatch?: Readonly>; + legacyMultiplicityDerivation?: boolean; }): Result { return ok( new LookupField( @@ -130,7 +131,9 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe params.lookupOptions, params.dbFieldName, params.dependencies, - params.isMultipleCellValue + params.isMultipleCellValue, + params.innerOptionsPatch, + params.legacyMultiplicityDerivation ) ); } @@ -146,6 +149,8 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe dbFieldName?: DbFieldName; dependencies?: ReadonlyArray; isMultipleCellValue?: boolean; + innerOptionsPatch?: Readonly>; + legacyMultiplicityDerivation?: boolean; }): Result { return LookupField.create(params); } @@ -189,6 +194,10 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe return this.lookupOptionsValue.toDto(); } + innerOptionsPatch(): Readonly> | undefined { + return this.innerOptionsPatchValue; + } + /** * The ID of the Link field used for lookup. */ @@ -276,31 +285,10 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe } duplicate(_params: FieldDuplicateParams): Result { - // Renaming uses duplicate with the same field id. - // Allow that path while still blocking true duplication. - if (!_params.newId.equals(this.id())) { - return err( - domainError.validation({ - code: 'field.lookup_cannot_duplicate', - message: - 'Lookup fields cannot be duplicated. Please duplicate the underlying link field instead.', - }) - ); - } - const isMultipleResult = this.isMultipleCellValue(); const isMultipleCellValue = isMultipleResult.isOk() ? isMultipleResult.value.isMultiple() : undefined; - const dbFieldNameResult = this.dbFieldName(); - const fallbackDbFieldNameResult = DbFieldName.rehydrate( - LookupField.fallbackDbFieldName(this.name().toString()) - ); - const dbFieldName = dbFieldNameResult.isOk() - ? dbFieldNameResult.value - : fallbackDbFieldNameResult.isOk() - ? fallbackDbFieldNameResult.value - : undefined; if (this.innerFieldValue) { return LookupField.create({ @@ -308,9 +296,10 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe name: _params.newName, innerField: this.innerFieldValue, lookupOptions: this.lookupOptionsValue, - dbFieldName, isMultipleCellValue, dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, + legacyMultiplicityDerivation: this.legacyMultiplicityDerivationEnabled, }); } @@ -318,9 +307,10 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe id: _params.newId, name: _params.newName, lookupOptions: this.lookupOptionsValue, - dbFieldName, isMultipleCellValue, dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, + legacyMultiplicityDerivation: this.legacyMultiplicityDerivationEnabled, }); } @@ -355,6 +345,9 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe domainError.notFound({ message: 'LookupField lookup field not found in foreign table' }) ); } + if (this.legacyMultiplicityDerivationEnabled) { + this.deriveMultiplicityOverride(linkField, lookupFieldResult.value); + } // 5. Resolve the inner field from the foreign table's lookup field // Nested lookups are supported - enables lookups across 3+ tables (e.g., Table A -> Table B -> Table C) @@ -373,6 +366,21 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe return this.ensureDependencies([this.linkFieldId(), ...(conditionFieldIds ?? [])]); } + private deriveMultiplicityOverride(linkField: LinkField, lookupField: Field): void { + if (this.isMultipleCellValueOverride !== undefined) { + return; + } + + const relationship = linkField.relationship().toString(); + const linkIsMultiple = relationship === 'manyMany' || relationship === 'oneMany'; + const lookupFieldValueType = lookupField.accept(new FieldValueTypeVisitor()); + const lookupTargetIsMultiple = lookupFieldValueType.isOk() + ? lookupFieldValueType.value.isMultipleCellValue.toBoolean() + : false; + + this.isMultipleCellValueOverride = linkIsMultiple || lookupTargetIsMultiple; + } + private ensureDependencies(nextDependencies: ReadonlyArray): Result { const deduped = nextDependencies.filter( (fieldId, index, array) => array.findIndex((candidate) => candidate.equals(fieldId)) === index @@ -448,6 +456,8 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe dbFieldName: dbFieldNameResult.isOk() ? dbFieldNameResult.value : undefined, isMultipleCellValue: isMultipleResult.value.isMultiple(), dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, + legacyMultiplicityDerivation: this.legacyMultiplicityDerivationEnabled, }); if (nextLookupFieldResult.isErr()) { return err(nextLookupFieldResult.error); @@ -487,6 +497,8 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe dbFieldName: dbFieldNameResult.isOk() ? dbFieldNameResult.value : undefined, isMultipleCellValue: newIsMultiple, dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, + legacyMultiplicityDerivation: this.legacyMultiplicityDerivationEnabled, }) : LookupField.createPending({ id: this.id(), @@ -495,6 +507,8 @@ export class LookupField extends Field implements ForeignTableRelatedField, OnTe dbFieldName: dbFieldNameResult.isOk() ? dbFieldNameResult.value : undefined, isMultipleCellValue: newIsMultiple, dependencies: this.dependencies(), + innerOptionsPatch: this.innerOptionsPatchValue, + legacyMultiplicityDerivation: this.legacyMultiplicityDerivationEnabled, }); if (nextLookupFieldResult.isErr()) return err(nextLookupFieldResult.error); specs.push(TableUpdateFieldTypeSpec.create(this, nextLookupFieldResult.value)); diff --git a/packages/v2/core/src/domain/table/fields/types/RollupField.ts b/packages/v2/core/src/domain/table/fields/types/RollupField.ts index 0d632bce8..eb53d3e70 100644 --- a/packages/v2/core/src/domain/table/fields/types/RollupField.ts +++ b/packages/v2/core/src/domain/table/fields/types/RollupField.ts @@ -21,11 +21,12 @@ import type { import type { FieldUpdateContext, OnTeableFieldUpdated } from '../OnTeableFieldUpdated'; import { FieldValueTypeVisitor } from '../visitors/FieldValueTypeVisitor'; import type { IFieldVisitor } from '../visitors/IFieldVisitor'; -import type { CellValueMultiplicity } from './CellValueMultiplicity'; +import { CellValueMultiplicity } from './CellValueMultiplicity'; import { CellValueType } from './CellValueType'; import type { DateTimeFormatting } from './DateTimeFormatting'; import { DateTimeFormatting as DateTimeFormattingValue } from './DateTimeFormatting'; import { FieldComputed } from './FieldComputed'; +import { FieldHasError } from './FieldHasError'; import { LinkField } from './LinkField'; import { NumberFormatting as NumberFormattingValue } from './NumberFormatting'; import type { NumberFormatting } from './NumberFormatting'; @@ -288,14 +289,22 @@ export class RollupField extends Field implements ForeignTableRelatedField, OnTe } cellValueType(): Result { - if (!this.cellValueTypeValue) + if (!this.cellValueTypeValue) { + if (this.hasError().isError()) { + return ok(CellValueType.string()); + } return err(domainError.invariant({ message: 'RollupField cell value type not set' })); + } return ok(this.cellValueTypeValue); } isMultipleCellValue(): Result { - if (!this.isMultipleCellValueValue) + if (!this.isMultipleCellValueValue) { + if (this.hasError().isError()) { + return ok(CellValueMultiplicity.single()); + } return err(domainError.invariant({ message: 'RollupField multiplicity not set' })); + } return ok(this.isMultipleCellValueValue); } @@ -373,7 +382,9 @@ export class RollupField extends Field implements ForeignTableRelatedField, OnTe cellValueType: valuesTypeResult.value.cellValueType, isMultipleCellValue: valuesTypeResult.value.isMultipleCellValue, }); - if (resolveResult.isErr()) return err(resolveResult.error); + if (resolveResult.isErr()) { + this.setHasError(FieldHasError.error()); + } } return this.ensureDependencies([linkFieldId]); diff --git a/packages/v2/core/src/domain/table/fields/visitors/FieldCreationSideEffectVisitor.spec.ts b/packages/v2/core/src/domain/table/fields/visitors/FieldCreationSideEffectVisitor.spec.ts index 266e05cea..8e2be5303 100644 --- a/packages/v2/core/src/domain/table/fields/visitors/FieldCreationSideEffectVisitor.spec.ts +++ b/packages/v2/core/src/domain/table/fields/visitors/FieldCreationSideEffectVisitor.spec.ts @@ -52,7 +52,7 @@ describe('FieldCreationSideEffectVisitor', () => { const hostPrimaryIdResult = createFieldId('d'); const foreignPrimaryIdResult = createFieldId('e'); const linkFieldIdResult = createFieldId('f'); - const linkFieldNameResult = FieldName.create('Link'); + const linkFieldNameResult = FieldName.create('Self'); [ baseIdResult, @@ -136,7 +136,7 @@ describe('FieldCreationSideEffectVisitor', () => { const hostPrimaryIdResult = createFieldId('j'); const foreignPrimaryIdResult = createFieldId('k'); const linkFieldIdResult = createFieldId('l'); - const linkFieldNameResult = FieldName.create('Link'); + const linkFieldNameResult = FieldName.create('Self'); [ baseIdResult, @@ -205,7 +205,7 @@ describe('FieldCreationSideEffectVisitor', () => { const tableIdResult = createTableId('n'); const primaryIdResult = createFieldId('o'); const linkFieldIdResult = createFieldId('p'); - const linkFieldNameResult = FieldName.create('Link'); + const linkFieldNameResult = FieldName.create('Self'); baseIdResult._unsafeUnwrap(); tableIdResult._unsafeUnwrap(); @@ -238,10 +238,16 @@ describe('FieldCreationSideEffectVisitor', () => { }); linkFieldResult._unsafeUnwrap(); + const tableWithLinkResult = table.update((mutator) => + mutator.addField(linkFieldResult._unsafeUnwrap(), { foreignTables: [table] }) + ); + tableWithLinkResult._unsafeUnwrap(); + const tableWithLink = tableWithLinkResult._unsafeUnwrap().table; + const sideEffectsResult = FieldCreationSideEffectVisitor.collect( [linkFieldResult._unsafeUnwrap()], { - table, + table: tableWithLink, foreignTables: [table], } ); @@ -251,12 +257,14 @@ describe('FieldCreationSideEffectVisitor', () => { const [effect] = sideEffectsResult._unsafeUnwrap(); expect(effect.foreignTable.id().equals(tableIdResult._unsafeUnwrap())).toBe(true); - const updatedResult = effect.mutateSpec.mutate(table); + const updatedResult = effect.mutateSpec.mutate(tableWithLink); updatedResult._unsafeUnwrap(); - expect( - updatedResult._unsafeUnwrap().getFields(buildFieldSpec((builder) => builder.isLink())) - ).toHaveLength(1); + const linkFields = updatedResult + ._unsafeUnwrap() + .getFields(buildFieldSpec((builder) => builder.isLink())) as ReadonlyArray; + expect(linkFields).toHaveLength(2); + expect(linkFields.map((field) => field.name().toString())).toEqual(['Self', 'Self (linked)']); }); it('errors when foreign table is missing', () => { diff --git a/packages/v2/core/src/domain/table/fields/visitors/FieldCreationSideEffectVisitor.ts b/packages/v2/core/src/domain/table/fields/visitors/FieldCreationSideEffectVisitor.ts index d94292506..f3c449190 100644 --- a/packages/v2/core/src/domain/table/fields/visitors/FieldCreationSideEffectVisitor.ts +++ b/packages/v2/core/src/domain/table/fields/visitors/FieldCreationSideEffectVisitor.ts @@ -150,7 +150,10 @@ export class FieldCreationSideEffectVisitor implements IFieldVisitor { color: field.color().toString(), }; if (maxCount) options.maxCount = maxCount.toNumber(); - if (maxCount && resetCount) options.resetCount = resetCount.toBoolean(); + if (resetCount) options.resetCount = resetCount.toBoolean(); if (workflow) options.workflow = workflow.toDto(); return ok(options); } diff --git a/packages/v2/core/src/domain/table/records/specs/RecordConditionOperators.ts b/packages/v2/core/src/domain/table/records/specs/RecordConditionOperators.ts index 3994849ed..10a87d1fa 100644 --- a/packages/v2/core/src/domain/table/records/specs/RecordConditionOperators.ts +++ b/packages/v2/core/src/domain/table/records/specs/RecordConditionOperators.ts @@ -227,6 +227,10 @@ export const getValidRecordConditionOperators = ( if (fieldType.equals(FieldType.link())) { operators = isMultiple ? [ + 'is', + 'isNot', + 'isAnyOf', + 'isNoneOf', 'hasAnyOf', 'hasAllOf', 'isExactly', diff --git a/packages/v2/core/src/domain/table/records/specs/RecordConditionSpecBuilder.spec.ts b/packages/v2/core/src/domain/table/records/specs/RecordConditionSpecBuilder.spec.ts index 97f4fdfa9..09501b294 100644 --- a/packages/v2/core/src/domain/table/records/specs/RecordConditionSpecBuilder.spec.ts +++ b/packages/v2/core/src/domain/table/records/specs/RecordConditionSpecBuilder.spec.ts @@ -306,6 +306,10 @@ describe('RecordCondition operators', () => { fields.linkMultiField.accept(new FieldValueTypeVisitor())._unsafeUnwrap() ); expect(linkMultiOperators).toEqual([ + 'is', + 'isNot', + 'isAnyOf', + 'isNoneOf', 'hasAnyOf', 'hasAllOf', 'isExactly', diff --git a/packages/v2/core/src/domain/table/resolveFormulaFields.ts b/packages/v2/core/src/domain/table/resolveFormulaFields.ts index c3a876a03..ab63c5e7d 100644 --- a/packages/v2/core/src/domain/table/resolveFormulaFields.ts +++ b/packages/v2/core/src/domain/table/resolveFormulaFields.ts @@ -5,6 +5,7 @@ import type { DomainError } from '../shared/DomainError'; import { domainError } from '../shared/DomainError'; import { FieldId } from './fields/FieldId'; import { FieldType } from './fields/FieldType'; +import { FieldHasError } from './fields/types/FieldHasError'; import type { FormulaField } from './fields/types/FormulaField'; import { FormulaField as FormulaFieldType } from './fields/types/FormulaField'; import { @@ -13,11 +14,16 @@ import { } from './fields/visitors/FieldValueTypeVisitor'; import type { Table } from './Table'; -export const resolveFormulaFields = (table: Table): Result => { +export const resolveFormulaFields = ( + table: Table, + options?: { + ignoreMissingReferenceOnExisting?: boolean; + strictFieldId?: FieldId; + } +): Result => { const fields = table.getFields(); const fieldById = new Map(fields.map((field) => [field.id().toString(), field] as const)); const dependenciesByFieldId = new Map>(); - const missingRefs: string[] = []; for (const field of fields) { if (!field.type().equals(FieldType.formula())) continue; @@ -29,6 +35,7 @@ export const resolveFormulaFields = (table: Table): Result => const uniqueRefs = Array.from(new Set(referenceResult.value.map((id) => id.toString()))); const dependencies: FieldId[] = []; + const missingRefs: string[] = []; for (const ref of uniqueRefs) { if (!fieldById.has(ref)) { @@ -40,7 +47,16 @@ export const resolveFormulaFields = (table: Table): Result => dependencies.push(fieldIdResult.value); } + const isStrictField = options?.strictFieldId ? field.id().equals(options.strictFieldId) : false; if (missingRefs.length > 0) { + if (options?.ignoreMissingReferenceOnExisting && !isStrictField) { + formulaField.setHasError(FieldHasError.error()); + const dependencyResult = formulaField.setDependencies(dependencies); + if (dependencyResult.isErr()) return err(dependencyResult.error); + dependenciesByFieldId.set(field.id().toString(), dependencies); + continue; + } + return err( domainError.notFound({ message: `Formula field references not found: ${missingRefs.join( @@ -50,6 +66,7 @@ export const resolveFormulaFields = (table: Table): Result => ); } + formulaField.setHasError(FieldHasError.ok()); const dependencyResult = formulaField.setDependencies(dependencies); if (dependencyResult.isErr()) return err(dependencyResult.error); dependenciesByFieldId.set(field.id().toString(), dependencies); @@ -106,12 +123,20 @@ export const resolveFormulaFields = (table: Table): Result => for (const field of dependencyOrder.ordered) { if (!field.type().equals(FieldType.formula())) continue; const formulaField = field as FormulaField; + if (formulaField.hasError().isError()) { + continue; + } const typeResult = formulaField.expression().getParsedValueType(valueTypes); if (typeResult.isErr()) { + const parseError = typeResult.error; + const parseMessage = `Parse formula expression ${formulaField.expression().toString()} error: ${parseError}`; return err( - domainError.unexpected({ - message: `Parse formula expression ${formulaField.expression().toString()} error: ${typeResult.error}`, - }) + // Preserve original domain tags (validation/invariant/etc.) so HTTP status mapping stays correct. + { + ...parseError, + message: parseMessage, + toString: () => parseMessage, + } ); } diff --git a/packages/v2/core/src/domain/table/specs/TableUpdateFieldDbFieldNameSpec.ts b/packages/v2/core/src/domain/table/specs/TableUpdateFieldDbFieldNameSpec.ts index 4e147f2fa..abc2c4373 100644 --- a/packages/v2/core/src/domain/table/specs/TableUpdateFieldDbFieldNameSpec.ts +++ b/packages/v2/core/src/domain/table/specs/TableUpdateFieldDbFieldNameSpec.ts @@ -47,10 +47,7 @@ export class TableUpdateFieldDbFieldNameSpec< } mutate(_t: Table): Result { - // The physical rename is handled by the persistence layer. - // The in-memory model is left unchanged because setDbFieldName rejects - // overwriting a rehydrated value; the repository re-derives names on load. - return ok(_t); + return _t.updateFieldDbFieldName(this.fieldIdValue, this.nextDbFieldNameValue); } accept(v: V): Result { diff --git a/packages/v2/core/src/domain/table/specs/TableUpdateViewColumnMetaSpec.ts b/packages/v2/core/src/domain/table/specs/TableUpdateViewColumnMetaSpec.ts index 48c8d3736..d198f705f 100644 --- a/packages/v2/core/src/domain/table/specs/TableUpdateViewColumnMetaSpec.ts +++ b/packages/v2/core/src/domain/table/specs/TableUpdateViewColumnMetaSpec.ts @@ -1,12 +1,14 @@ -import { ok } from 'neverthrow'; +import { err, ok } from 'neverthrow'; import type { Result } from 'neverthrow'; import type { DomainError } from '../../shared/DomainError'; import { MutateOnlySpec } from '../../shared/specification/MutateOnlySpec'; import type { FieldId } from '../fields/FieldId'; -import type { Table } from '../Table'; -import type { ViewColumnMeta } from '../views/ViewColumnMeta'; +import { Table } from '../Table'; +import type { View } from '../views/View'; +import { ViewColumnMeta } from '../views/ViewColumnMeta'; import type { ViewId } from '../views/ViewId'; +import { CloneViewVisitor } from '../views/visitors/CloneViewVisitor'; import type { ITableSpecVisitor } from './ITableSpecVisitor'; export type TableViewColumnMetaUpdate = { @@ -39,12 +41,132 @@ export class TableUpdateViewColumnMetaSpec< return updatesResult.map((updates) => new TableUpdateViewColumnMetaSpec(updates)); } + static forDuplicatePlacement(params: { + table: Table; + sourceFieldId: FieldId; + newFieldId: FieldId; + targetViewId: ViewId; + }): Result { + const { table, sourceFieldId, newFieldId, targetViewId } = params; + + const updatesResult = table + .views() + .reduce, DomainError>>( + (acc, view) => + acc.andThen((updates) => + view.columnMeta().andThen((columnMeta) => { + if (!view.id().equals(targetViewId)) { + return ok([...updates, { viewId: view.id(), fieldId: newFieldId, columnMeta }]); + } + + const sourceOrder = columnMeta.toDto()[sourceFieldId.toString()]?.order; + if (typeof sourceOrder !== 'number') { + return ok([...updates, { viewId: view.id(), fieldId: newFieldId, columnMeta }]); + } + + const raw = columnMeta.toDto(); + const newFieldKey = newFieldId.toString(); + const nextGreater = Object.entries(raw) + .filter(([key, value]) => key !== newFieldKey && typeof value?.order === 'number') + .map(([, value]) => value.order as number) + .filter((order) => order > sourceOrder) + .sort((a, b) => a - b)[0]; + + const targetOrder = + nextGreater !== undefined ? (sourceOrder + nextGreater) / 2 : sourceOrder + 1; + + const nextMetaResult = ViewColumnMeta.create({ + ...raw, + [newFieldKey]: { + ...(raw[newFieldKey] ?? {}), + order: targetOrder, + }, + }); + return nextMetaResult.map((nextMeta) => [ + ...updates, + { + viewId: view.id(), + fieldId: newFieldId, + columnMeta: nextMeta, + }, + ]); + }) + ), + ok([]) + ); + + return updatesResult.map((updates) => new TableUpdateViewColumnMetaSpec(updates)); + } + updates(): ReadonlyArray { return this.updatesValue; } mutate(t: Table): Result { - return ok(t); + if (this.updatesValue.length === 0) { + return ok(t); + } + + const updatesByViewId = new Map(); + for (const update of this.updatesValue) { + updatesByViewId.set(update.viewId.toString(), update.columnMeta); + } + + const nextViews: View[] = []; + for (const view of t.views()) { + const nextColumnMeta = updatesByViewId.get(view.id().toString()); + if (!nextColumnMeta) { + nextViews.push(view); + continue; + } + + const cloneResult = view.accept(new CloneViewVisitor()); + if (cloneResult.isErr()) { + return err(cloneResult.error); + } + + const clone = cloneResult.value; + const setColumnMetaResult = clone.setColumnMeta(nextColumnMeta); + if (setColumnMetaResult.isErr()) { + return err(setColumnMetaResult.error); + } + + const queryDefaultsResult = view.queryDefaults(); + if (queryDefaultsResult.isErr()) { + return err(queryDefaultsResult.error); + } + + const setQueryDefaultsResult = clone.setQueryDefaults(queryDefaultsResult.value); + if (setQueryDefaultsResult.isErr()) { + return err(setQueryDefaultsResult.error); + } + + nextViews.push(clone); + } + + const nextTableResult = Table.rehydrate({ + id: t.id(), + baseId: t.baseId(), + name: t.name(), + fields: t.getFields(), + views: nextViews, + primaryFieldId: t.primaryFieldId(), + }); + if (nextTableResult.isErr()) { + return nextTableResult; + } + + const dbTableNameResult = t.dbTableName(); + if (dbTableNameResult.isErr()) { + return ok(nextTableResult.value); + } + + const setDbTableNameResult = nextTableResult.value.setDbTableName(dbTableNameResult.value); + if (setDbTableNameResult.isErr()) { + return err(setDbTableNameResult.error); + } + + return ok(nextTableResult.value); } accept(v: V): Result { diff --git a/packages/v2/core/src/domain/table/specs/__tests__/TableUpdateViewColumnMetaSpec.spec.ts b/packages/v2/core/src/domain/table/specs/__tests__/TableUpdateViewColumnMetaSpec.spec.ts new file mode 100644 index 000000000..ef8e8b149 --- /dev/null +++ b/packages/v2/core/src/domain/table/specs/__tests__/TableUpdateViewColumnMetaSpec.spec.ts @@ -0,0 +1,62 @@ +import { describe, expect, it } from 'vitest'; + +import { BaseId } from '../../../base/BaseId'; +import { FieldId } from '../../fields/FieldId'; +import { FieldName } from '../../fields/FieldName'; +import { Table } from '../../Table'; +import { TableName } from '../../TableName'; +import { TableUpdateViewColumnMetaSpec } from '../TableUpdateViewColumnMetaSpec'; + +const createBaseId = (seed: string) => BaseId.create(`bse${seed.repeat(16)}`)._unsafeUnwrap(); + +describe('TableUpdateViewColumnMetaSpec', () => { + it('places duplicated field right after source field in target view', () => { + const baseId = createBaseId('a'); + const builder = Table.builder() + .withBaseId(baseId) + .withName(TableName.create('Duplicate View Order')._unsafeUnwrap()); + + builder + .field() + .singleLineText() + .withName(FieldName.create('Title')._unsafeUnwrap()) + .primary() + .done(); + builder.field().number().withName(FieldName.create('Amount')._unsafeUnwrap()).done(); + builder.field().singleLineText().withName(FieldName.create('Note')._unsafeUnwrap()).done(); + builder.view().defaultGrid().done(); + + const table = builder.build()._unsafeUnwrap(); + const sourceField = table.getFields().find((field) => field.name().toString() === 'Amount'); + expect(sourceField).toBeTruthy(); + if (!sourceField) return; + + const duplicatedField = sourceField + .duplicate({ + newId: FieldId.mustGenerate(), + newName: FieldName.create('Amount (copy)')._unsafeUnwrap(), + baseId: table.baseId(), + tableId: table.id(), + }) + ._unsafeUnwrap(); + + const withDuplicated = table.addField(duplicatedField)._unsafeUnwrap(); + const targetView = withDuplicated.views()[0]!; + + const spec = TableUpdateViewColumnMetaSpec.forDuplicatePlacement({ + table: withDuplicated, + sourceFieldId: sourceField.id(), + newFieldId: duplicatedField.id(), + targetViewId: targetView.id(), + })._unsafeUnwrap(); + + const update = spec.updates()[0]!; + const dto = update.columnMeta.toDto(); + const sourceOrder = dto[sourceField.id().toString()]?.order; + const duplicatedOrder = dto[duplicatedField.id().toString()]?.order; + + expect(typeof sourceOrder).toBe('number'); + expect(typeof duplicatedOrder).toBe('number'); + expect((duplicatedOrder as number) > (sourceOrder as number)).toBe(true); + }); +}); diff --git a/packages/v2/core/src/domain/table/specs/visitors/TableEventGeneratingSpecVisitor.ts b/packages/v2/core/src/domain/table/specs/visitors/TableEventGeneratingSpecVisitor.ts index fe29bb6fc..8534e099d 100644 --- a/packages/v2/core/src/domain/table/specs/visitors/TableEventGeneratingSpecVisitor.ts +++ b/packages/v2/core/src/domain/table/specs/visitors/TableEventGeneratingSpecVisitor.ts @@ -1,4 +1,4 @@ -import { ok } from 'neverthrow'; +import { err, ok } from 'neverthrow'; import type { Result } from 'neverthrow'; import type { DomainError } from '../../../shared/DomainError'; @@ -95,16 +95,42 @@ export class TableEventGeneratingSpecVisitor implements ITableSpecVisitor } visitTableAddField(spec: TableAddFieldSpec): Result { + const viewOrdersResult = this.collectViewOrders(spec.field().id()); + if (viewOrdersResult.isErr()) { + return err(viewOrdersResult.error); + } + this.events.push( FieldCreated.create({ tableId: this.table.id(), baseId: this.table.baseId(), fieldId: spec.field().id(), + viewOrders: viewOrdersResult.value, }) ); return ok(undefined); } + private collectViewOrders( + fieldId: FieldId + ): Result>, DomainError> { + const fieldIdStr = fieldId.toString(); + const viewOrders: Record = {}; + + for (const view of this.table.views()) { + const viewMetaResult = view.columnMeta(); + if (viewMetaResult.isErr()) { + return err(viewMetaResult.error); + } + const order = viewMetaResult.value.toDto()[fieldIdStr]?.order; + if (typeof order === 'number') { + viewOrders[view.id().toString()] = order; + } + } + + return ok(viewOrders); + } + visitTableAddSelectOptions(spec: TableAddSelectOptionsSpec): Result { const options = spec.options(); if (options.length > 0) { diff --git a/packages/v2/core/src/domain/table/specs/visitors/TableSpecEventVisitor.ts b/packages/v2/core/src/domain/table/specs/visitors/TableSpecEventVisitor.ts index eb3454fad..827db2dd4 100644 --- a/packages/v2/core/src/domain/table/specs/visitors/TableSpecEventVisitor.ts +++ b/packages/v2/core/src/domain/table/specs/visitors/TableSpecEventVisitor.ts @@ -1,4 +1,4 @@ -import { ok } from 'neverthrow'; +import { err, ok } from 'neverthrow'; import type { Result } from 'neverthrow'; import type { DomainError } from '../../../shared/DomainError'; @@ -9,6 +9,7 @@ import { FieldDeleted } from '../../events/FieldDeleted'; import { FieldUpdated } from '../../events/FieldUpdated'; import { TableRenamed } from '../../events/TableRenamed'; import { ViewColumnMetaUpdated } from '../../events/ViewColumnMetaUpdated'; +import type { FieldId } from '../../fields/FieldId'; import type { Table } from '../../Table'; import type { RemoveSymmetricLinkFieldSpec, @@ -118,17 +119,43 @@ export class TableSpecEventVisitor implements ITableSpecVisitor { visitTableAddField(spec: TableAddFieldSpec>): Result { const field = spec.field(); + const viewOrdersResult = this.collectViewOrders(field.id()); + if (viewOrdersResult.isErr()) { + return err(viewOrdersResult.error); + } + this.eventsCollected.push( FieldCreated.create({ tableId: this.table.id(), baseId: this.table.baseId(), fieldId: field.id(), + viewOrders: viewOrdersResult.value, }) ); return ok(undefined); } + private collectViewOrders( + fieldId: FieldId + ): Result>, DomainError> { + const fieldIdStr = fieldId.toString(); + const viewOrders: Record = {}; + + for (const view of this.table.views()) { + const viewMetaResult = view.columnMeta(); + if (viewMetaResult.isErr()) { + return err>, DomainError>(viewMetaResult.error); + } + const order = viewMetaResult.value.toDto()[fieldIdStr]?.order; + if (typeof order === 'number') { + viewOrders[view.id().toString()] = order; + } + } + + return ok(viewOrders); + } + visitTableAddSelectOptions( _spec: TableAddSelectOptionsSpec> ): Result { diff --git a/packages/v2/core/src/domain/table/specs/visitors/__tests__/TableEventGeneratingSpecVisitor.spec.ts b/packages/v2/core/src/domain/table/specs/visitors/__tests__/TableEventGeneratingSpecVisitor.spec.ts index c710a047c..1ec87ba26 100644 --- a/packages/v2/core/src/domain/table/specs/visitors/__tests__/TableEventGeneratingSpecVisitor.spec.ts +++ b/packages/v2/core/src/domain/table/specs/visitors/__tests__/TableEventGeneratingSpecVisitor.spec.ts @@ -134,11 +134,7 @@ describe('TableEventGeneratingSpecVisitor', () => { precision: 2, symbol: '$', })._unsafeUnwrap(); - const spec = UpdateNumberFormattingSpec.create( - fieldId, - previousFormatting, - nextFormatting - ); + const spec = UpdateNumberFormattingSpec.create(fieldId, previousFormatting, nextFormatting); spec.accept(visitor)._unsafeUnwrap(); const events = visitor.getEvents(); diff --git a/packages/v2/core/src/ports/mappers/TableMapper.ts b/packages/v2/core/src/ports/mappers/TableMapper.ts index d1d41ba75..49b3f6129 100644 --- a/packages/v2/core/src/ports/mappers/TableMapper.ts +++ b/packages/v2/core/src/ports/mappers/TableMapper.ts @@ -209,6 +209,7 @@ export type ILookupOptionsDTO = { linkFieldId: string; lookupFieldId: string; foreignTableId: string; + relationship?: 'oneOne' | 'manyMany' | 'oneMany' | 'manyOne'; filter?: IFieldConditionDTO['filter']; sort?: IFieldConditionDTO['sort']; limit?: number; @@ -218,6 +219,7 @@ export type ITableFieldBaseDTO = { id: string; name: string; description?: string | null; + aiConfig?: unknown | null; dbFieldName?: string; dbFieldType?: string; isComputed?: boolean; diff --git a/packages/v2/core/src/ports/mappers/defaults/DefaultTableMapper.spec.ts b/packages/v2/core/src/ports/mappers/defaults/DefaultTableMapper.spec.ts index d6e6a78af..3436f3ffd 100644 --- a/packages/v2/core/src/ports/mappers/defaults/DefaultTableMapper.spec.ts +++ b/packages/v2/core/src/ports/mappers/defaults/DefaultTableMapper.spec.ts @@ -13,6 +13,7 @@ import { CellValueMultiplicity } from '../../../domain/table/fields/types/CellVa import { CellValueType } from '../../../domain/table/fields/types/CellValueType'; import { CheckboxField } from '../../../domain/table/fields/types/CheckboxField'; import { ConditionalLookupField } from '../../../domain/table/fields/types/ConditionalLookupField'; +import { ConditionalLookupOptions } from '../../../domain/table/fields/types/ConditionalLookupOptions'; import { DateDefaultValue } from '../../../domain/table/fields/types/DateDefaultValue'; import { DateField } from '../../../domain/table/fields/types/DateField'; import { DateTimeFormatting } from '../../../domain/table/fields/types/DateTimeFormatting'; @@ -453,6 +454,74 @@ describe('DefaultTableMapper', () => { expect((conditionalLookupField as ConditionalLookupField).isPending()).toBe(true); }); + it('merges conditional lookup inner options patch when persisting', () => { + const baseId = BaseId.create(`bse${'m'.repeat(16)}`)._unsafeUnwrap(); + const tableId = TableId.create(`tbl${'m'.repeat(16)}`)._unsafeUnwrap(); + const primaryFieldId = FieldId.create(`fld${'m'.repeat(16)}`)._unsafeUnwrap(); + const innerFieldId = FieldId.create(`fld${'n'.repeat(16)}`)._unsafeUnwrap(); + const conditionalLookupId = FieldId.create(`fld${'o'.repeat(16)}`)._unsafeUnwrap(); + + const builder = Table.builder() + .withBaseId(baseId) + .withId(tableId) + .withName(TableName.create('Conditional Lookup Patch')._unsafeUnwrap()); + builder + .field() + .singleLineText() + .withId(primaryFieldId) + .withName(FieldName.create('Name')._unsafeUnwrap()) + .primary() + .done(); + builder.addFieldFromResult( + ConditionalLookupField.create({ + id: conditionalLookupId, + name: FieldName.create('Amount Lookup')._unsafeUnwrap(), + innerField: NumberField.create({ + id: innerFieldId, + name: FieldName.create('Amount')._unsafeUnwrap(), + formatting: NumberFormatting.create({ type: 'decimal', precision: 2 })._unsafeUnwrap(), + })._unsafeUnwrap(), + conditionalLookupOptions: ConditionalLookupOptions.create({ + foreignTableId: `tbl${'p'.repeat(16)}`, + lookupFieldId: `fld${'q'.repeat(16)}`, + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: primaryFieldId.toString(), operator: 'is', value: 'open' }], + }, + }, + })._unsafeUnwrap(), + innerOptionsPatch: { + formatting: { + type: 'currency', + precision: 1, + symbol: '¥', + }, + }, + }) + ); + builder.view().defaultGrid().done(); + const table = builder.build()._unsafeUnwrap(); + + const mapper = new DefaultTableMapper(); + const dto = mapper.toDTO(table)._unsafeUnwrap(); + const persisted = dto.fields.find((field) => field.id === conditionalLookupId.toString()) as + | (typeof dto.fields)[number] + | undefined; + + expect(persisted?.type).toBe('conditionalLookup'); + if (!persisted || persisted.type !== 'conditionalLookup') { + return; + } + expect(persisted.innerOptions).toEqual({ + formatting: { + type: 'currency', + precision: 1, + symbol: '¥', + }, + }); + }); + it('falls back to pending lookup when legacy link-lookup inner options are invalid', () => { const table = buildTable(); const mapper = new DefaultTableMapper(); diff --git a/packages/v2/core/src/ports/mappers/defaults/DefaultTableMapper.ts b/packages/v2/core/src/ports/mappers/defaults/DefaultTableMapper.ts index 3a9fb9966..3f2786e83 100644 --- a/packages/v2/core/src/ports/mappers/defaults/DefaultTableMapper.ts +++ b/packages/v2/core/src/ports/mappers/defaults/DefaultTableMapper.ts @@ -196,11 +196,41 @@ const parseTrackedFieldIds = (raw: unknown): Result, Doma return sequenceResults(raw.map((entry) => FieldId.create(entry))); }; +const unwrapConditionalLookupInner = ( + dto: ITableFieldPersistenceDTO +): { innerType?: ITableFieldPersistenceDTO['type']; innerOptions?: unknown } => { + if (dto.type !== 'conditionalLookup') { + return { + innerType: dto.type, + innerOptions: 'options' in dto ? dto.options : undefined, + }; + } + + if (dto.innerType && dto.innerType !== 'conditionalLookup') { + return { + innerType: dto.innerType as ITableFieldPersistenceDTO['type'], + innerOptions: dto.innerOptions, + }; + } + + return { + innerType: undefined, + innerOptions: undefined, + }; +}; + class FieldToPersistenceVisitor implements IFieldVisitor { + constructor( + private readonly resolveLookupRelationship?: ( + linkFieldId: string + ) => ILinkFieldOptionsDTO['relationship'] | undefined + ) {} + private baseField(field: Field): { id: string; name: string; description?: string | null; + aiConfig?: unknown | null; dbFieldName?: string; dbFieldType?: string; notNull?: boolean; @@ -217,10 +247,11 @@ class FieldToPersistenceVisitor implements IFieldVisitor inner.accept(this)) - .map((innerDto: ITableFieldPersistenceDTO) => ({ - ...innerDto, - id: field.id().toString(), - name: field.name().toString(), - isLookup: true, - isConditionalLookup, - lookupOptions, - isComputed: true, - ...(isMultipleCellValue != null ? { isMultipleCellValue } : {}), - })); + .map((innerDto: ITableFieldPersistenceDTO) => { + const innerOptionsPatch = field.innerOptionsPatch(); + const mergedInnerOptions: ITableFieldPersistenceDTO['options'] | undefined = + innerOptionsPatch && Object.keys(innerOptionsPatch).length > 0 + ? { + ...((innerDto.options && + typeof innerDto.options === 'object' && + !Array.isArray(innerDto.options) + ? (innerDto.options as Record) + : {}) as Record), + ...innerOptionsPatch, + } + : innerDto.options; + + return { + ...innerDto, + id: field.id().toString(), + name: field.name().toString(), + isLookup: true, + isConditionalLookup, + lookupOptions: lookupOptionsWithRelationship, + isComputed: true, + ...(mergedInnerOptions !== undefined ? { options: mergedInnerOptions } : {}), + ...(isMultipleCellValue != null ? { isMultipleCellValue } : {}), + } as ITableFieldPersistenceDTO; + }); } visitConditionalRollupField( @@ -661,21 +719,38 @@ class FieldToPersistenceVisitor implements IFieldVisitor - inner.accept(this).map((innerDto: ITableFieldPersistenceDTO) => ({ - ...baseDto, - type: 'conditionalLookup' as const, - options, - innerType: innerDto.type, - innerOptions: 'options' in innerDto ? innerDto.options : undefined, - isComputed: true, - ...(isMultipleCellValue != null ? { isMultipleCellValue } : {}), - })) + inner.accept(this).map((innerDto: ITableFieldPersistenceDTO) => { + const unwrapped = unwrapConditionalLookupInner(innerDto); + const innerOptionsPatch = field.innerOptionsPatch(); + const mergedInnerOptions: ITableFieldPersistenceDTO['options'] | undefined = + innerOptionsPatch && Object.keys(innerOptionsPatch).length > 0 + ? { + ...((unwrapped.innerOptions && + typeof unwrapped.innerOptions === 'object' && + !Array.isArray(unwrapped.innerOptions) + ? (unwrapped.innerOptions as Record) + : {}) as Record), + ...innerOptionsPatch, + } + : (unwrapped.innerOptions as ITableFieldPersistenceDTO['options'] | undefined); + return { + ...baseDto, + type: 'conditionalLookup' as const, + options, + innerType: unwrapped.innerType, + innerOptions: mergedInnerOptions, + isComputed: true, + ...(isMultipleCellValue != null ? { isMultipleCellValue } : {}), + }; + }) ); } } -const mapFieldToDto = (field: Field): Result => - field.accept(new FieldToPersistenceVisitor()); +const mapFieldToDto = ( + field: Field, + visitor: FieldToPersistenceVisitor +): Result => field.accept(visitor); class ViewToPersistenceVisitor implements IViewVisitor { visitGridView(view: GridView): Result { @@ -723,7 +798,21 @@ const mapViewToDto = (view: View): Result export class DefaultTableMapper implements ITableMapper { toDTO(table: Table): Result { - return sequenceResults(table.getFields().map(mapFieldToDto)).andThen((fields) => + const relationshipByLinkFieldId = new Map(); + for (const field of table.getFields()) { + if (!(field instanceof LinkField)) { + continue; + } + relationshipByLinkFieldId.set(field.id().toString(), field.relationship().toString()); + } + + const fieldVisitor = new FieldToPersistenceVisitor((linkFieldId) => + relationshipByLinkFieldId.get(linkFieldId) + ); + + return sequenceResults( + table.getFields().map((field) => mapFieldToDto(field, fieldVisitor)) + ).andThen((fields) => sequenceResults(table.views().map(mapViewToDto)).map((views) => ({ id: table.id().toString(), baseId: table.baseId().toString(), @@ -838,7 +927,8 @@ export class DefaultTableMapper implements ITableMapper { private mapConditionalLookupInnerField( dto: Extract ): Result { - if (!dto.innerType || dto.innerType === 'conditionalLookup') { + const unwrapped = unwrapConditionalLookupInner(dto); + if (!unwrapped.innerType || unwrapped.innerType === 'conditionalLookup') { return ok(undefined); } @@ -847,8 +937,8 @@ export class DefaultTableMapper implements ITableMapper { this.mapBaseFieldToDomain({ id: innerId.toString(), name: dto.name, - type: dto.innerType as ITableFieldPersistenceDTO['type'], - options: dto.innerOptions as never, + type: unwrapped.innerType as ITableFieldPersistenceDTO['type'], + options: unwrapped.innerOptions as never, } as ITableFieldPersistenceDTO) ) .andThen((innerField) => { @@ -1184,6 +1274,7 @@ export class DefaultTableMapper implements ITableMapper { ) .andThen((field) => this.applyFieldValidation(field, dto.notNull, dto.unique)) .andThen((field) => this.applyDescription(field, dto.description)) + .andThen((field) => this.applyAiConfig(field, dto.aiConfig)) .andThen((field) => this.applyDbFieldName(field, dto.dbFieldName)) .andThen((field) => this.applyDbFieldType(field, dto.dbFieldType)) .andThen((field) => this.applyHasError(field, dto.hasError)); @@ -1197,6 +1288,14 @@ export class DefaultTableMapper implements ITableMapper { return field.setDescription(description).map(() => field); } + private applyAiConfig( + field: Field, + aiConfig: unknown | null | undefined + ): Result { + if (aiConfig === undefined) return ok(field); + return field.setAiConfig(aiConfig).map(() => field); + } + private mapViewToDomain(dto: ITableViewPersistenceDTO): Result { return ViewId.create(dto.id).andThen((id) => ViewName.create(dto.name).andThen((name) => { diff --git a/packages/v2/core/src/ports/memory/AsyncMemoryEventBus.ts b/packages/v2/core/src/ports/memory/AsyncMemoryEventBus.ts index ce05b4fb7..584340d6c 100644 --- a/packages/v2/core/src/ports/memory/AsyncMemoryEventBus.ts +++ b/packages/v2/core/src/ports/memory/AsyncMemoryEventBus.ts @@ -54,8 +54,27 @@ const defaultScheduler: AsyncEventBusScheduler = (task) => { export class AsyncMemoryEventBus implements IEventBus { private readonly publishedEvents: IDomainEvent[] = []; - private readonly queue: Array<{ context: IExecutionContext; event: IDomainEvent }> = []; + private readonly queue: Array<{ context: IExecutionContext; event: IDomainEvent; seq: number }> = + []; + private readonly waiters: Array<{ targetSeq: number; resolve: () => void }> = []; private draining = false; + private nextSeq = 0; + private processedSeq = -1; + + private shouldAwait(events: ReadonlyArray): boolean { + if (!events.length) return false; + + const awaitableEventNames = new Set([ + 'FieldCreated', + 'FieldUpdated', + 'FieldDeleted', + 'FieldDuplicated', + 'FieldOptionsAdded', + 'ViewColumnMetaUpdated', + ]); + + return events.every((event) => awaitableEventNames.has(event.name.toString())); + } constructor( private readonly handlerResolver: IHandlerResolver, @@ -70,9 +89,14 @@ export class AsyncMemoryEventBus implements IEventBus { context: IExecutionContext, event: IDomainEvent ): Promise> { + const shouldAwait = this.shouldAwait([event]); + const wasDraining = this.draining; this.enrichWithRequestId(context, event); this.publishedEvents.push(event); - this.enqueue(context, [event]); + const targetSeq = this.enqueue(context, [event]); + if (shouldAwait && !wasDraining) { + await this.waitUntilProcessed(targetSeq); + } return ok(undefined); } @@ -80,11 +104,19 @@ export class AsyncMemoryEventBus implements IEventBus { context: IExecutionContext, events: ReadonlyArray ): Promise> { + if (!events.length) { + return ok(undefined); + } + const shouldAwait = this.shouldAwait(events); + const wasDraining = this.draining; for (const event of events) { this.enrichWithRequestId(context, event); } this.publishedEvents.push(...events); - this.enqueue(context, events); + const targetSeq = this.enqueue(context, events); + if (shouldAwait && !wasDraining) { + await this.waitUntilProcessed(targetSeq); + } return ok(undefined); } @@ -94,14 +126,41 @@ export class AsyncMemoryEventBus implements IEventBus { } } - private enqueue(context: IExecutionContext, events: ReadonlyArray): void { + private enqueue(context: IExecutionContext, events: ReadonlyArray): number { + let targetSeq = this.processedSeq; for (const event of events) { - this.queue.push({ context, event }); + const seq = this.nextSeq; + this.nextSeq += 1; + targetSeq = seq; + this.queue.push({ context, event, seq }); } if (!this.draining) { this.draining = true; this.scheduleDrain(); } + return targetSeq; + } + + private waitUntilProcessed(targetSeq: number): Promise { + if (targetSeq <= this.processedSeq) { + return Promise.resolve(); + } + + return new Promise((resolve) => { + this.waiters.push({ targetSeq, resolve }); + }); + } + + private resolveWaiters(): void { + if (!this.waiters.length) return; + + for (let i = this.waiters.length - 1; i >= 0; i--) { + const waiter = this.waiters[i]; + if (waiter.targetSeq <= this.processedSeq) { + this.waiters.splice(i, 1); + waiter.resolve(); + } + } } private scheduleDrain(): void { @@ -116,6 +175,8 @@ export class AsyncMemoryEventBus implements IEventBus { const next = this.queue.shift(); if (!next) continue; await this.dispatch(next.context, next.event); + this.processedSeq = next.seq; + this.resolveWaiters(); } this.draining = false; if (this.queue.length > 0) { diff --git a/packages/v2/core/src/schemas/field/tableField.schema.ts b/packages/v2/core/src/schemas/field/tableField.schema.ts index 25cd51da9..9f72289a1 100644 --- a/packages/v2/core/src/schemas/field/tableField.schema.ts +++ b/packages/v2/core/src/schemas/field/tableField.schema.ts @@ -1,6 +1,6 @@ import { z } from 'zod'; -import { fieldColorSchema } from '../../domain/table/fields/types/FieldColor'; +import { fieldColorSchema, fieldColorValues } from '../../domain/table/fields/types/FieldColor'; import { TIME_ZONE_LIST } from '../../domain/table/fields/types/TimeZone'; import { cellValueTypeSchema, @@ -45,8 +45,29 @@ export const selectChoiceSchema = z.object({ color: fieldColorSchema, }); +const normalizedSelectChoicesSchema = z.preprocess((value) => { + const toArray = Array.isArray(value) + ? value + : value && typeof value === 'object' + ? Object.values(value as Record) + : []; + + return toArray.map((item, index) => { + const choice = item && typeof item === 'object' ? (item as Record) : {}; + const color = + typeof choice.color === 'string' && fieldColorValues.includes(choice.color as never) + ? choice.color + : fieldColorValues[index % fieldColorValues.length]; + return { + id: typeof choice.id === 'string' ? choice.id : undefined, + name: String(choice.name ?? ''), + color, + }; + }); +}, z.array(selectChoiceSchema)); + export const selectOptionsSchema = z.object({ - choices: z.array(selectChoiceSchema).optional(), + choices: normalizedSelectChoicesSchema.optional(), defaultValue: z.union([z.string(), z.array(z.string())]).optional(), preventAutoNewOptions: z.boolean().optional(), }); @@ -109,8 +130,11 @@ export const linkOptionsSchema = z baseId: z.string().optional(), relationship: linkRelationshipSchema, foreignTableId: z.string(), - lookupFieldId: z.string(), + lookupFieldId: z.string().optional(), isOneWay: z.boolean().optional(), + fkHostTableName: z.string().optional(), + selfKeyName: z.string().optional(), + foreignKeyName: z.string().optional(), symmetricFieldId: z.string().optional(), filterByViewId: z.string().nullable().optional(), visibleFieldIds: z.array(z.string()).nullable().optional(), @@ -204,7 +228,9 @@ export const conditionalLookupOptionsSchema = z const tableFieldCommonShape = { id: z.string().optional(), name: z.string().optional(), + dbFieldName: z.string().optional(), description: z.string().nullable().optional(), + aiConfig: z.unknown().nullable().optional(), isPrimary: z.boolean().optional(), notNull: z.boolean().optional(), unique: z.boolean().optional(), @@ -300,6 +326,9 @@ export const tableFieldInputSchema = z.discriminatedUnion('type', [ tableFieldSchema({ type: z.literal('lookup'), options: lookupOptionsSchema, + innerOptions: z.record(z.string(), z.unknown()).optional(), + legacyMultiplicityDerivation: z.boolean().optional(), + isMultipleCellValue: z.boolean().optional(), }).strict(), tableFieldSchema({ type: z.literal('conditionalRollup'), @@ -311,6 +340,8 @@ export const tableFieldInputSchema = z.discriminatedUnion('type', [ tableFieldSchema({ type: z.literal('conditionalLookup'), options: conditionalLookupOptionsSchema, + innerOptions: z.record(z.string(), z.unknown()).optional(), + isMultipleCellValue: z.boolean().optional(), }).strict(), ]); diff --git a/packages/v2/e2e/src/create-field/README.md b/packages/v2/e2e/src/create-field/README.md new file mode 100644 index 000000000..40b064642 --- /dev/null +++ b/packages/v2/e2e/src/create-field/README.md @@ -0,0 +1,35 @@ +# Create Field E2E Tests + +This directory contains Teable v2 e2e coverage for create-field scenarios. + +## Directory structure + +``` +create-field/ +├── README.md +├── button/ +│ └── button.spec.ts +├── conditionalLookup/ +│ └── cross-base.spec.ts +├── conditionalRollup/ +│ ├── conditionalRollup.spec.ts +│ └── cross-base.spec.ts +├── formula/ +│ └── formula.spec.ts +├── lookup/ +│ ├── cross-base.spec.ts +│ └── lookup.spec.ts +├── rollup/ +│ ├── cross-base.spec.ts +│ └── rollup.spec.ts +└── singleLineText/ + └── singleLineText.spec.ts +``` + +## Conventions + +- Organize tests by created field type (one folder per type). +- Keep cross-base behavior in `cross-base.spec.ts` per type. +- Prefer assertions on both: + - field metadata after creation + - computed value behavior after `ctx.drainOutbox()` diff --git a/packages/v2/e2e/src/create-field/button/button.spec.ts b/packages/v2/e2e/src/create-field/button/button.spec.ts new file mode 100644 index 000000000..bb0877c00 --- /dev/null +++ b/packages/v2/e2e/src/create-field/button/button.spec.ts @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { beforeAll, describe, expect, test } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: button v1 parity', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + test('button field resetCount=true is persisted in field options', async () => { + let tableId: string | undefined; + + try { + const table = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-button'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + tableId = table.id; + + const updated = await ctx.createField({ + baseId: ctx.baseId, + tableId, + field: { + type: 'button', + name: 'Button', + options: { + label: 'Button', + color: 'teal', + resetCount: true, + workflow: { + id: 'wfl00000000000000001', + name: 'Workflow', + isActive: true, + }, + }, + }, + }); + const buttonField = updated.fields.find((f) => f.name === 'Button') as + | { id: string; options?: { resetCount?: boolean } } + | undefined; + if (!buttonField) throw new Error('Missing button field'); + expect(buttonField.options?.resetCount).toBe(true); + + const refreshed = await ctx.getTableById(table.id); + const refreshedButton = refreshed.fields.find((f) => f.id === buttonField.id) as + | { options?: { resetCount?: boolean } } + | undefined; + expect(refreshedButton?.options?.resetCount).toBe(true); + } finally { + if (tableId) await ctx.deleteTable(tableId).catch(() => undefined); + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/conditionalLookup/cross-base.spec.ts b/packages/v2/e2e/src/create-field/conditionalLookup/cross-base.spec.ts new file mode 100644 index 000000000..2359da8b0 --- /dev/null +++ b/packages/v2/e2e/src/create-field/conditionalLookup/cross-base.spec.ts @@ -0,0 +1,126 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { createBaseOkResponseSchema } from '@teable/v2-contract-http'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: conditionalLookup cross-base', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + let fieldIdCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + const createFieldId = () => { + const suffix = fieldIdCounter.toString(36).padStart(16, '0'); + fieldIdCounter += 1; + return `fld${suffix}`; + }; + + const createBase = async (name: string) => { + const response = await fetch(`${ctx.baseUrl}/bases/create`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ name, spaceId: 'space_test' }), + }); + const rawBody = await response.json(); + if (response.status !== 201) { + throw new Error(`CreateBase failed: ${JSON.stringify(rawBody)}`); + } + const parsed = createBaseOkResponseSchema.safeParse(rawBody); + if (!parsed.success || !parsed.data.ok) { + throw new Error(`CreateBase parse failed: ${JSON.stringify(rawBody)}`); + } + return parsed.data.data.base.id; + }; + + const deleteTableWithBaseId = async (baseId: string, tableId: string) => { + const response = await fetch(`${ctx.baseUrl}/tables/delete`, { + method: 'DELETE', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ baseId, tableId }), + }); + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Failed to delete table ${tableId} in base ${baseId}: ${errorText}`); + } + }; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + it('creates conditional lookup across base boundaries', async () => { + let hostTableId: string | undefined; + let foreignBaseId: string | undefined; + let foreignTableId: string | undefined; + + try { + foreignBaseId = await createBase(nextName('v2-create-cl-foreign-base')); + + const foreignNameFieldId = createFieldId(); + const foreignStatusFieldId = createFieldId(); + const foreignTable = await ctx.createTable({ + baseId: foreignBaseId, + name: nextName('v2-create-cl-foreign-table'), + fields: [ + { type: 'singleLineText', id: foreignNameFieldId, name: 'Name' }, + { type: 'singleLineText', id: foreignStatusFieldId, name: 'Status' }, + ], + records: [ + { fields: { [foreignNameFieldId]: 'Item-A', [foreignStatusFieldId]: 'Active' } }, + { fields: { [foreignNameFieldId]: 'Item-B', [foreignStatusFieldId]: 'Inactive' } }, + { fields: { [foreignNameFieldId]: 'Item-C', [foreignStatusFieldId]: 'Active' } }, + ], + }); + foreignTableId = foreignTable.id; + + const hostPrimaryFieldId = createFieldId(); + const hostTable = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-cl-host-table'), + fields: [{ type: 'singleLineText', id: hostPrimaryFieldId, name: 'Host Name' }], + records: [{ fields: { [hostPrimaryFieldId]: 'Host-1' } }], + }); + hostTableId = hostTable.id; + + const conditionalLookupFieldId = createFieldId(); + const updatedTable = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'conditionalLookup', + id: conditionalLookupFieldId, + name: 'Active Items', + options: { + foreignTableId: foreignTable.id, + lookupFieldId: foreignNameFieldId, + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: foreignStatusFieldId, operator: 'is', value: 'Active' }], + }, + }, + }, + }, + }); + + const createdField = updatedTable.fields.find( + (field) => field.id === conditionalLookupFieldId + ) as { isLookup?: boolean; conditionalLookupOptions?: unknown } | undefined; + expect(createdField?.isLookup).toBe(true); + expect(createdField?.conditionalLookupOptions).toBeTruthy(); + + await ctx.drainOutbox(); + + const hostRecords = await ctx.listRecords(hostTable.id); + expect(hostRecords[0]?.fields[conditionalLookupFieldId]).toEqual(['Item-A', 'Item-C']); + } finally { + await ctx.drainOutbox().catch(() => undefined); + if (hostTableId) { + await ctx.deleteTable(hostTableId).catch(() => undefined); + } + if (foreignBaseId && foreignTableId) { + await deleteTableWithBaseId(foreignBaseId, foreignTableId).catch(() => undefined); + } + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/conditionalRollup/conditionalRollup.spec.ts b/packages/v2/e2e/src/create-field/conditionalRollup/conditionalRollup.spec.ts new file mode 100644 index 000000000..9b609b01d --- /dev/null +++ b/packages/v2/e2e/src/create-field/conditionalRollup/conditionalRollup.spec.ts @@ -0,0 +1,133 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { beforeAll, describe, expect, test } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: conditionalRollup v1 parity', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + test('evaluates equality filter comparing link titles to host text', async () => { + let tagsTableId: string | undefined; + let foreignTableId: string | undefined; + let hostTableId: string | undefined; + + try { + const tagsTable = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-tags'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + tagsTableId = tagsTable.id; + const tagPrimaryId = tagsTable.fields.find((f) => f.isPrimary)?.id; + if (!tagPrimaryId) throw new Error('Missing tags primary field'); + + const tagAId = (await ctx.createRecord(tagsTable.id, { [tagPrimaryId]: 'TagA' })).id; + const tagBId = (await ctx.createRecord(tagsTable.id, { [tagPrimaryId]: 'TagB' })).id; + + const foreignTable = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-foreign'), + fields: [ + { type: 'singleLineText', name: 'Title', isPrimary: true }, + { + type: 'link', + name: 'Tags', + options: { + relationship: 'manyMany', + foreignTableId: tagsTable.id, + lookupFieldId: tagPrimaryId, + isOneWay: true, + }, + }, + { type: 'number', name: 'Amount' }, + ], + }); + foreignTableId = foreignTable.id; + const foreignTagsId = foreignTable.fields.find((f) => f.name === 'Tags')?.id; + const foreignAmountId = foreignTable.fields.find((f) => f.name === 'Amount')?.id; + if (!foreignTagsId || !foreignAmountId) throw new Error('Missing foreign fields'); + + const foreignRecord1 = await ctx.createRecord(foreignTable.id, { Title: 'r1', Amount: 10 }); + const foreignRecord2 = await ctx.createRecord(foreignTable.id, { Title: 'r2', Amount: 20 }); + const foreignRecord3 = await ctx.createRecord(foreignTable.id, { Title: 'r3', Amount: 5 }); + + await ctx.updateRecord(foreignTable.id, foreignRecord1.id, { + [foreignTagsId]: [{ id: tagAId }], + }); + await ctx.updateRecord(foreignTable.id, foreignRecord2.id, { + [foreignTagsId]: [{ id: tagBId }], + }); + await ctx.updateRecord(foreignTable.id, foreignRecord3.id, { + [foreignTagsId]: [{ id: tagAId }, { id: tagBId }], + }); + + const hostTable = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-host'), + fields: [{ type: 'singleLineText', name: 'TagName', isPrimary: true }], + }); + hostTableId = hostTable.id; + const hostTagNameId = hostTable.fields.find((f) => f.name === 'TagName')?.id; + if (!hostTagNameId) throw new Error('Missing host text field'); + + await ctx.createRecord(hostTable.id, { [hostTagNameId]: 'TagA' }); + await ctx.createRecord(hostTable.id, { [hostTagNameId]: 'TagB' }); + await ctx.createRecord(hostTable.id, { [hostTagNameId]: 'TagC' }); + + const tableWithRollup = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'conditionalRollup', + name: 'Sum By Tag Title', + options: { expression: 'sum({values})' }, + config: { + foreignTableId: foreignTable.id, + lookupFieldId: foreignAmountId, + condition: { + filter: { + conjunction: 'and', + filterSet: [ + { + fieldId: foreignTagsId, + operator: 'is', + value: hostTagNameId, + isSymbol: true, + }, + ], + }, + }, + }, + }, + }); + const rollupFieldId = tableWithRollup.fields.find((f) => f.name === 'Sum By Tag Title')?.id; + if (!rollupFieldId) throw new Error('Missing conditional rollup field'); + + await ctx.drainOutbox(); + + const hostRecords = await ctx.listRecords(hostTable.id, { limit: 10, offset: 0 }); + const hostPrimaryId = hostTable.fields.find((f) => f.isPrimary)?.id; + if (!hostPrimaryId) throw new Error('Missing host primary field'); + + const byTagName = new Map( + hostRecords.map((record) => [ + String(record.fields[hostPrimaryId] ?? ''), + record.fields[rollupFieldId], + ]) + ); + expect(byTagName.get('TagA')).toBe(15); + expect(byTagName.get('TagB')).toBe(25); + expect(byTagName.get('TagC')).toBe(0); + } finally { + if (hostTableId) await ctx.deleteTable(hostTableId).catch(() => undefined); + if (foreignTableId) await ctx.deleteTable(foreignTableId).catch(() => undefined); + if (tagsTableId) await ctx.deleteTable(tagsTableId).catch(() => undefined); + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/conditionalRollup/cross-base.spec.ts b/packages/v2/e2e/src/create-field/conditionalRollup/cross-base.spec.ts new file mode 100644 index 000000000..f381b3558 --- /dev/null +++ b/packages/v2/e2e/src/create-field/conditionalRollup/cross-base.spec.ts @@ -0,0 +1,150 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { createBaseOkResponseSchema } from '@teable/v2-contract-http'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: conditionalRollup cross-base', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + let fieldIdCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + const createFieldId = () => { + const suffix = fieldIdCounter.toString(36).padStart(16, '0'); + fieldIdCounter += 1; + return `fld${suffix}`; + }; + + const createBase = async (name: string) => { + const response = await fetch(`${ctx.baseUrl}/bases/create`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ name, spaceId: 'space_test' }), + }); + const rawBody = await response.json(); + if (response.status !== 201) { + throw new Error(`CreateBase failed: ${JSON.stringify(rawBody)}`); + } + const parsed = createBaseOkResponseSchema.safeParse(rawBody); + if (!parsed.success || !parsed.data.ok) { + throw new Error(`CreateBase parse failed: ${JSON.stringify(rawBody)}`); + } + return parsed.data.data.base.id; + }; + + const deleteTableWithBaseId = async (baseId: string, tableId: string) => { + const response = await fetch(`${ctx.baseUrl}/tables/delete`, { + method: 'DELETE', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ baseId, tableId }), + }); + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Failed to delete table ${tableId} in base ${baseId}: ${errorText}`); + } + }; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + it('creates conditional rollup across base boundaries', async () => { + let hostTableId: string | undefined; + let foreignBaseId: string | undefined; + let foreignTableId: string | undefined; + + try { + foreignBaseId = await createBase(nextName('v2-create-cr-foreign-base')); + + const foreignNameFieldId = createFieldId(); + const foreignStatusFieldId = createFieldId(); + const foreignAmountFieldId = createFieldId(); + const foreignTable = await ctx.createTable({ + baseId: foreignBaseId, + name: nextName('v2-create-cr-foreign-table'), + fields: [ + { type: 'singleLineText', id: foreignNameFieldId, name: 'Name' }, + { type: 'singleLineText', id: foreignStatusFieldId, name: 'Status' }, + { type: 'number', id: foreignAmountFieldId, name: 'Amount' }, + ], + records: [ + { + fields: { + [foreignNameFieldId]: 'Item-A', + [foreignStatusFieldId]: 'Active', + [foreignAmountFieldId]: 10, + }, + }, + { + fields: { + [foreignNameFieldId]: 'Item-B', + [foreignStatusFieldId]: 'Inactive', + [foreignAmountFieldId]: 100, + }, + }, + { + fields: { + [foreignNameFieldId]: 'Item-C', + [foreignStatusFieldId]: 'Active', + [foreignAmountFieldId]: 5, + }, + }, + ], + }); + foreignTableId = foreignTable.id; + + const hostPrimaryFieldId = createFieldId(); + const hostTable = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-cr-host-table'), + fields: [{ type: 'singleLineText', id: hostPrimaryFieldId, name: 'Host Name' }], + records: [{ fields: { [hostPrimaryFieldId]: 'Host-1' } }], + }); + hostTableId = hostTable.id; + + const conditionalRollupFieldId = createFieldId(); + const updatedTable = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'conditionalRollup', + id: conditionalRollupFieldId, + name: 'Active Amount Sum', + options: { + expression: 'sum({values})', + timeZone: 'utc', + }, + config: { + foreignTableId: foreignTable.id, + lookupFieldId: foreignAmountFieldId, + condition: { + filter: { + conjunction: 'and', + filterSet: [{ fieldId: foreignStatusFieldId, operator: 'is', value: 'Active' }], + }, + }, + }, + }, + }); + + const createdField = updatedTable.fields.find( + (field) => field.id === conditionalRollupFieldId + ) as { type?: string; options?: { expression?: string } } | undefined; + expect(createdField?.type).toBe('conditionalRollup'); + expect(createdField?.options?.expression).toBe('sum({values})'); + + await ctx.drainOutbox(); + + const hostRecords = await ctx.listRecords(hostTable.id); + expect(hostRecords[0]?.fields[conditionalRollupFieldId]).toBe(15); + } finally { + await ctx.drainOutbox().catch(() => undefined); + if (hostTableId) { + await ctx.deleteTable(hostTableId).catch(() => undefined); + } + if (foreignBaseId && foreignTableId) { + await deleteTableWithBaseId(foreignBaseId, foreignTableId).catch(() => undefined); + } + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/formula/formula.spec.ts b/packages/v2/e2e/src/create-field/formula/formula.spec.ts new file mode 100644 index 000000000..e3cbed393 --- /dev/null +++ b/packages/v2/e2e/src/create-field/formula/formula.spec.ts @@ -0,0 +1,69 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { beforeAll, describe, expect, test } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: formula v1 parity', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + test('formula update keeps default timezone when showAs is removed', async () => { + let tableId: string | undefined; + + try { + const table = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-formula-timezone'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + tableId = table.id; + + const tableWithFormula = await ctx.createField({ + baseId: ctx.baseId, + tableId, + field: { + type: 'formula', + name: 'F', + options: { + expression: '"text"', + showAs: { type: 'email' }, + }, + }, + }); + const formulaField = tableWithFormula.fields.find((f) => f.name === 'F'); + if (!formulaField) throw new Error('Missing formula field'); + + const updated = await ctx.updateField({ + tableId, + fieldId: formulaField.id, + field: { + type: 'formula', + options: { + expression: '"text"', + showAs: null, + }, + }, + }); + + const updatedField = updated.fields.find((f) => f.id === formulaField.id); + const options = updatedField?.options as { + expression?: string; + showAs?: unknown; + timeZone?: string; + }; + + expect(options.expression).toBe('"text"'); + expect(options.showAs).toBeUndefined(); + expect(options.timeZone?.toLowerCase()).toBe( + Intl.DateTimeFormat().resolvedOptions().timeZone.toLowerCase() + ); + } finally { + if (tableId) await ctx.deleteTable(tableId).catch(() => undefined); + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/lookup/cross-base.spec.ts b/packages/v2/e2e/src/create-field/lookup/cross-base.spec.ts new file mode 100644 index 000000000..21bd4203c --- /dev/null +++ b/packages/v2/e2e/src/create-field/lookup/cross-base.spec.ts @@ -0,0 +1,145 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { createBaseOkResponseSchema } from '@teable/v2-contract-http'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: lookup cross-base', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + let fieldIdCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + const createFieldId = () => { + const suffix = fieldIdCounter.toString(36).padStart(16, '0'); + fieldIdCounter += 1; + return `fld${suffix}`; + }; + + const createBase = async (name: string) => { + const response = await fetch(`${ctx.baseUrl}/bases/create`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ name, spaceId: 'space_test' }), + }); + const rawBody = await response.json(); + if (response.status !== 201) { + throw new Error(`CreateBase failed: ${JSON.stringify(rawBody)}`); + } + const parsed = createBaseOkResponseSchema.safeParse(rawBody); + if (!parsed.success || !parsed.data.ok) { + throw new Error(`CreateBase parse failed: ${JSON.stringify(rawBody)}`); + } + return parsed.data.data.base.id; + }; + + const deleteTableWithBaseId = async (baseId: string, tableId: string) => { + const response = await fetch(`${ctx.baseUrl}/tables/delete`, { + method: 'DELETE', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ baseId, tableId }), + }); + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Failed to delete table ${tableId} in base ${baseId}: ${errorText}`); + } + }; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + it('creates lookup through one-way cross-base link', async () => { + let hostTableId: string | undefined; + let foreignBaseId: string | undefined; + let foreignTableId: string | undefined; + + try { + foreignBaseId = await createBase(nextName('v2-create-lookup-foreign-base')); + + const foreignPrimaryFieldId = createFieldId(); + const foreignTable = await ctx.createTable({ + baseId: foreignBaseId, + name: nextName('v2-create-lookup-foreign-table'), + fields: [{ type: 'singleLineText', id: foreignPrimaryFieldId, name: 'Product Name' }], + }); + foreignTableId = foreignTable.id; + + const foreignRecord = await ctx.createRecord(foreignTable.id, { + [foreignPrimaryFieldId]: 'Prod-A', + }); + + const hostPrimaryFieldId = createFieldId(); + const hostTable = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-lookup-host-table'), + fields: [{ type: 'singleLineText', id: hostPrimaryFieldId, name: 'Order Name' }], + }); + hostTableId = hostTable.id; + + const linkFieldName = 'Product Link'; + const tableAfterLink = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'link', + id: createFieldId(), + name: linkFieldName, + options: { + baseId: foreignBaseId, + relationship: 'manyOne', + foreignTableId: foreignTable.id, + lookupFieldId: foreignPrimaryFieldId, + isOneWay: true, + }, + }, + }); + const linkFieldId = tableAfterLink.fields.find((field) => field.name === linkFieldName)?.id; + if (!linkFieldId) { + throw new Error('Failed to resolve created link field'); + } + + const lookupFieldId = createFieldId(); + const tableAfterLookup = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'lookup', + id: lookupFieldId, + name: 'Product Name (Lookup)', + options: { + linkFieldId, + foreignTableId: foreignTable.id, + lookupFieldId: foreignPrimaryFieldId, + }, + }, + }); + const lookupField = tableAfterLookup.fields.find((field) => field.id === lookupFieldId) as + | { isLookup?: boolean; lookupOptions?: unknown } + | undefined; + expect(lookupField?.isLookup).toBe(true); + expect(lookupField?.lookupOptions).toBeTruthy(); + + const hostRecord = await ctx.createRecord(hostTable.id, { + [hostPrimaryFieldId]: 'Order-1', + }); + + await ctx.updateRecord(hostTable.id, hostRecord.id, { + [linkFieldId]: { id: foreignRecord.id }, + }); + + await ctx.drainOutbox(); + + const hostRecords = await ctx.listRecords(hostTable.id); + const updatedHostRecord = hostRecords.find((record) => record.id === hostRecord.id); + expect(updatedHostRecord?.fields[lookupFieldId]).toEqual(['Prod-A']); + } finally { + await ctx.drainOutbox().catch(() => undefined); + if (hostTableId) { + await ctx.deleteTable(hostTableId).catch(() => undefined); + } + if (foreignBaseId && foreignTableId) { + await deleteTableWithBaseId(foreignBaseId, foreignTableId).catch(() => undefined); + } + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/lookup/lookup.spec.ts b/packages/v2/e2e/src/create-field/lookup/lookup.spec.ts new file mode 100644 index 000000000..9e487f410 --- /dev/null +++ b/packages/v2/e2e/src/create-field/lookup/lookup.spec.ts @@ -0,0 +1,97 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { beforeAll, describe, expect, test } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: lookup v1 parity', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + test('lookup keeps relationship and marks hasError after link converted', async () => { + let table1Id: string | undefined; + let table2Id: string | undefined; + + try { + const table2 = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-lookup-foreign'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + table2Id = table2.id; + const table2PrimaryId = table2.fields.find((f) => f.isPrimary)?.id; + if (!table2PrimaryId) throw new Error('Missing foreign primary field'); + const foreignRecord = await ctx.createRecord(table2.id, { [table2PrimaryId]: 'x' }); + + const table1 = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-lookup-host'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + table1Id = table1.id; + const hostRecord = await ctx.createRecord(table1.id, { Name: 'host' }); + + const tableWithLink = await ctx.createField({ + baseId: ctx.baseId, + tableId: table1.id, + field: { + type: 'link', + name: 'Link', + options: { + relationship: 'manyOne', + foreignTableId: table2.id, + lookupFieldId: table2PrimaryId, + isOneWay: true, + }, + }, + }); + const linkField = tableWithLink.fields.find((f) => f.name === 'Link'); + if (!linkField) throw new Error('Missing link field'); + + const tableWithLookup = await ctx.createField({ + baseId: ctx.baseId, + tableId: table1.id, + field: { + type: 'lookup', + name: 'LookupName', + options: { + linkFieldId: linkField.id, + foreignTableId: table2.id, + lookupFieldId: table2PrimaryId, + }, + }, + }); + const lookupField = tableWithLookup.fields.find((f) => f.name === 'LookupName'); + if (!lookupField) throw new Error('Missing lookup field'); + + await ctx.updateRecord(table1.id, hostRecord.id, { + [linkField.id]: { id: foreignRecord.id }, + }); + await ctx.drainOutbox(); + + await ctx.updateField({ + tableId: table1.id, + fieldId: linkField.id, + field: { + type: 'singleLineText', + options: {}, + }, + }); + await ctx.drainOutbox(); + + const refreshed = await ctx.getTableById(table1.id); + const lookupAfter = refreshed.fields.find((f) => f.id === lookupField.id) as + | { hasError?: boolean; lookupOptions?: { relationship?: string } } + | undefined; + expect(lookupAfter?.hasError).toBe(true); + expect(lookupAfter?.lookupOptions?.relationship).toBe('manyMany'); + } finally { + if (table1Id) await ctx.deleteTable(table1Id).catch(() => undefined); + if (table2Id) await ctx.deleteTable(table2Id).catch(() => undefined); + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/rollup/cross-base.spec.ts b/packages/v2/e2e/src/create-field/rollup/cross-base.spec.ts new file mode 100644 index 000000000..336644541 --- /dev/null +++ b/packages/v2/e2e/src/create-field/rollup/cross-base.spec.ts @@ -0,0 +1,155 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { createBaseOkResponseSchema } from '@teable/v2-contract-http'; +import { beforeAll, describe, expect, it } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: rollup cross-base', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + let fieldIdCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + const createFieldId = () => { + const suffix = fieldIdCounter.toString(36).padStart(16, '0'); + fieldIdCounter += 1; + return `fld${suffix}`; + }; + + const createBase = async (name: string) => { + const response = await fetch(`${ctx.baseUrl}/bases/create`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ name, spaceId: 'space_test' }), + }); + const rawBody = await response.json(); + if (response.status !== 201) { + throw new Error(`CreateBase failed: ${JSON.stringify(rawBody)}`); + } + const parsed = createBaseOkResponseSchema.safeParse(rawBody); + if (!parsed.success || !parsed.data.ok) { + throw new Error(`CreateBase parse failed: ${JSON.stringify(rawBody)}`); + } + return parsed.data.data.base.id; + }; + + const deleteTableWithBaseId = async (baseId: string, tableId: string) => { + const response = await fetch(`${ctx.baseUrl}/tables/delete`, { + method: 'DELETE', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ baseId, tableId }), + }); + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Failed to delete table ${tableId} in base ${baseId}: ${errorText}`); + } + }; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + it('creates rollup through one-way cross-base link', async () => { + let hostTableId: string | undefined; + let foreignBaseId: string | undefined; + let foreignTableId: string | undefined; + + try { + foreignBaseId = await createBase(nextName('v2-create-rollup-foreign-base')); + + const foreignPrimaryFieldId = createFieldId(); + const foreignAmountFieldId = createFieldId(); + const foreignTable = await ctx.createTable({ + baseId: foreignBaseId, + name: nextName('v2-create-rollup-foreign-table'), + fields: [ + { type: 'singleLineText', id: foreignPrimaryFieldId, name: 'Product Name' }, + { type: 'number', id: foreignAmountFieldId, name: 'Amount' }, + ], + }); + foreignTableId = foreignTable.id; + + const foreignRecord1 = await ctx.createRecord(foreignTable.id, { + [foreignPrimaryFieldId]: 'Prod-A', + [foreignAmountFieldId]: 10, + }); + const foreignRecord2 = await ctx.createRecord(foreignTable.id, { + [foreignPrimaryFieldId]: 'Prod-B', + [foreignAmountFieldId]: 5, + }); + + const hostPrimaryFieldId = createFieldId(); + const hostTable = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-rollup-host-table'), + fields: [{ type: 'singleLineText', id: hostPrimaryFieldId, name: 'Order Name' }], + }); + hostTableId = hostTable.id; + + const linkFieldName = 'Product Link'; + const tableAfterLink = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'link', + id: createFieldId(), + name: linkFieldName, + options: { + baseId: foreignBaseId, + relationship: 'manyMany', + foreignTableId: foreignTable.id, + lookupFieldId: foreignPrimaryFieldId, + isOneWay: true, + }, + }, + }); + const linkFieldId = tableAfterLink.fields.find((field) => field.name === linkFieldName)?.id; + if (!linkFieldId) { + throw new Error('Failed to resolve created link field'); + } + + const rollupFieldId = createFieldId(); + const tableAfterRollup = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'rollup', + id: rollupFieldId, + name: 'Total Amount', + options: { + expression: 'sum({values})', + timeZone: 'utc', + }, + config: { + linkFieldId, + foreignTableId: foreignTable.id, + lookupFieldId: foreignAmountFieldId, + }, + }, + }); + const rollupField = tableAfterRollup.fields.find((field) => field.id === rollupFieldId); + expect(rollupField?.type).toBe('rollup'); + + const hostRecord = await ctx.createRecord(hostTable.id, { + [hostPrimaryFieldId]: 'Order-1', + }); + + await ctx.updateRecord(hostTable.id, hostRecord.id, { + [linkFieldId]: [{ id: foreignRecord1.id }, { id: foreignRecord2.id }], + }); + + await ctx.drainOutbox(); + + const hostRecords = await ctx.listRecords(hostTable.id); + const updatedHostRecord = hostRecords.find((record) => record.id === hostRecord.id); + expect(updatedHostRecord?.fields[rollupFieldId]).toBe(15); + } finally { + await ctx.drainOutbox().catch(() => undefined); + if (hostTableId) { + await ctx.deleteTable(hostTableId).catch(() => undefined); + } + if (foreignBaseId && foreignTableId) { + await deleteTableWithBaseId(foreignBaseId, foreignTableId).catch(() => undefined); + } + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/rollup/rollup.spec.ts b/packages/v2/e2e/src/create-field/rollup/rollup.spec.ts new file mode 100644 index 000000000..8344125ed --- /dev/null +++ b/packages/v2/e2e/src/create-field/rollup/rollup.spec.ts @@ -0,0 +1,112 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { beforeAll, describe, expect, test } from 'vitest'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: rollup v1 parity', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + test('create record with errored lookup and rollup fields returns undefined values', async () => { + let table1Id: string | undefined; + let table2Id: string | undefined; + + try { + const table1 = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-record-host'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + table1Id = table1.id; + + const table2 = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-record-foreign'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + table2Id = table2.id; + const table2PrimaryId = table2.fields.find((f) => f.isPrimary)?.id; + if (!table2PrimaryId) throw new Error('Missing foreign primary'); + const foreignRecord = await ctx.createRecord(table2.id, { [table2PrimaryId]: 'f1' }); + + const table2WithTarget = await ctx.createField({ + baseId: ctx.baseId, + tableId: table2.id, + field: { type: 'singleLineText', name: 'ToDelete' }, + }); + const targetField = table2WithTarget.fields.find((f) => f.name === 'ToDelete'); + const foreignPrimaryId = table2WithTarget.fields.find((f) => f.isPrimary)?.id; + if (!targetField || !foreignPrimaryId) throw new Error('Missing target/primary field'); + + const table1WithLink = await ctx.createField({ + baseId: ctx.baseId, + tableId: table1.id, + field: { + type: 'link', + name: 'Link', + options: { + relationship: 'manyOne', + foreignTableId: table2.id, + lookupFieldId: foreignPrimaryId, + isOneWay: true, + }, + }, + }); + const linkField = table1WithLink.fields.find((f) => f.name === 'Link'); + if (!linkField) throw new Error('Missing link field'); + + const table1WithLookup = await ctx.createField({ + baseId: ctx.baseId, + tableId: table1.id, + field: { + type: 'lookup', + name: 'LookupErr', + options: { + linkFieldId: linkField.id, + foreignTableId: table2.id, + lookupFieldId: targetField.id, + }, + }, + }); + const lookupField = table1WithLookup.fields.find((f) => f.name === 'LookupErr'); + if (!lookupField) throw new Error('Missing lookup field'); + + const table1WithRollup = await ctx.createField({ + baseId: ctx.baseId, + tableId: table1.id, + field: { + type: 'rollup', + name: 'RollupErr', + options: { + expression: 'sum({values})', + }, + config: { + linkFieldId: linkField.id, + foreignTableId: table2.id, + lookupFieldId: targetField.id, + }, + }, + }); + const rollupField = table1WithRollup.fields.find((f) => f.name === 'RollupErr'); + if (!rollupField) throw new Error('Missing rollup field'); + + await ctx.deleteField({ tableId: table2.id, fieldId: targetField.id }); + + const created = await ctx.createRecord(table1.id, { + [linkField.id]: { id: foreignRecord.id }, + }); + await ctx.drainOutbox(); + + expect(created.fields[lookupField.id]).toBeUndefined(); + expect(created.fields[rollupField.id]).toBeUndefined(); + } finally { + if (table1Id) await ctx.deleteTable(table1Id).catch(() => undefined); + if (table2Id) await ctx.deleteTable(table2Id).catch(() => undefined); + } + }); +}); diff --git a/packages/v2/e2e/src/create-field/singleLineText/singleLineText.spec.ts b/packages/v2/e2e/src/create-field/singleLineText/singleLineText.spec.ts new file mode 100644 index 000000000..c80cedd61 --- /dev/null +++ b/packages/v2/e2e/src/create-field/singleLineText/singleLineText.spec.ts @@ -0,0 +1,138 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { beforeAll, describe, expect, test } from 'vitest'; +import { createFieldErrorResponseSchema } from '@teable/v2-contract-http'; +import { getSharedTestContext, type SharedTestContext } from '../../shared/globalTestContext'; + +describe('create-field: singleLineText v1 parity', () => { + let ctx: SharedTestContext; + let nameCounter = 0; + + const nextName = (prefix: string) => `${prefix}-${nameCounter++}`; + + beforeAll(async () => { + ctx = await getSharedTestContext(); + }); + + test('create/update field preserves dbFieldName', async () => { + let tableId: string | undefined; + + try { + const table = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-dbfield'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + tableId = table.id; + + const tableAfterCreate = await ctx.createField({ + baseId: ctx.baseId, + tableId, + field: { + type: 'singleLineText', + name: 'TextField', + dbFieldName: 'fld_custom_a', + }, + }); + const createdField = tableAfterCreate.fields.find((f) => f.name === 'TextField'); + if (!createdField) throw new Error('Missing created field'); + expect(createdField.dbFieldName).toBe('fld_custom_a'); + + const tableAfterUpdate = await ctx.updateField({ + tableId, + fieldId: createdField.id, + field: { + type: 'singleLineText', + dbFieldName: 'fld_custom_b', + }, + }); + const updatedField = tableAfterUpdate.fields.find((f) => f.id === createdField.id); + expect(updatedField?.dbFieldName).toBe('fld_custom_b'); + } finally { + if (tableId) await ctx.deleteTable(tableId).catch(() => undefined); + } + }); + + test('rejects duplicate dbFieldName on create', async () => { + let tableId: string | undefined; + + try { + const table = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-dbfield-duplicate'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + tableId = table.id; + + const first = await ctx.createField({ + baseId: ctx.baseId, + tableId, + field: { + type: 'singleLineText', + name: 'TextField-1', + dbFieldName: 'fld_custom_duplicate', + }, + }); + + expect(first.fields.some((f) => f.dbFieldName === 'fld_custom_duplicate')).toBe(true); + + const response = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId, + field: { + type: 'singleLineText', + name: 'TextField-2', + dbFieldName: 'fld_custom_duplicate', + }, + }), + }); + + expect(response.status).toBe(400); + const raw = await response.json(); + const parsed = createFieldErrorResponseSchema.safeParse(raw); + expect(parsed.success).toBe(true); + if (parsed.success) { + expect(parsed.data.ok).toBe(false); + expect(parsed.data.error.message).toContain('already exists in this table'); + } + } finally { + if (tableId) await ctx.deleteTable(tableId).catch(() => undefined); + } + }); + + test('primary field unique toggles back to false explicitly', async () => { + let tableId: string | undefined; + + try { + const table = await ctx.createTable({ + baseId: ctx.baseId, + name: nextName('v2-create-reg-primary-unique'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + tableId = table.id; + const primaryFieldId = table.fields.find((f) => f.isPrimary)?.id; + if (!primaryFieldId) throw new Error('Missing primary field'); + + await ctx.updateField({ + tableId, + fieldId: primaryFieldId, + field: { unique: true }, + }); + + const afterDrop = await ctx.updateField({ + tableId, + fieldId: primaryFieldId, + field: { unique: false }, + }); + + const primaryAfter = afterDrop.fields.find((f) => f.id === primaryFieldId) as + | { unique?: boolean } + | undefined; + expect(primaryAfter?.unique).toBe(false); + } finally { + if (tableId) await ctx.deleteTable(tableId).catch(() => undefined); + } + }); +}); diff --git a/packages/v2/e2e/src/createField.e2e.spec.ts b/packages/v2/e2e/src/createField.e2e.spec.ts index 5bff1b3eb..4d56e622e 100644 --- a/packages/v2/e2e/src/createField.e2e.spec.ts +++ b/packages/v2/e2e/src/createField.e2e.spec.ts @@ -11,13 +11,30 @@ import { ROLLUP_FUNCTIONS, getRollupFunctionsByCellValueType, } from '@teable/v2-core'; +import { sql } from 'kysely'; import { afterAll, beforeAll, describe, expect, it, test } from 'vitest'; import { getSharedTestContext, type SharedTestContext } from './shared/globalTestContext'; describe('v2 http createField (e2e)', () => { + const getSearchIndexName = (tableName: string, dbFieldName: string, fieldId: string) => { + const prefix = 'idx_trgm'; + const maxLen = 63; + const delimiterLen = 3; + const maxTableDbNameLen = maxLen - fieldId.length - prefix.length - delimiterLen; + const tableDbNameLen = + maxTableDbNameLen < tableName.length ? maxTableDbNameLen : tableName.length; + const dbFieldNameLen = + maxTableDbNameLen < tableName.length + ? 0 + : maxLen - fieldId.length - prefix.length - tableDbNameLen - delimiterLen; + const abbDbFieldName = dbFieldName.slice(0, dbFieldNameLen); + return `${prefix}_${tableName.slice(0, tableDbNameLen)}_${abbDbFieldName}_${fieldId}`; + }; + let ctx: SharedTestContext; let tableId: string; let tablePrimaryFieldId: string; + let tablePrimaryDbFieldName: string; let foreignTableId: string; let foreignPrimaryFieldId: string; let fieldIdCounter = 0; @@ -86,7 +103,11 @@ describe('v2 http createField (e2e)', () => { if (!primaryField) { throw new Error('Failed to resolve primary field'); } + if (typeof primaryField.dbFieldName !== 'string') { + throw new Error('Failed to resolve primary db field name'); + } tablePrimaryFieldId = primaryField.id; + tablePrimaryDbFieldName = primaryField.dbFieldName; const foreignResponse = await fetch(`${ctx.baseUrl}/tables/create`, { method: 'POST', @@ -129,6 +150,122 @@ describe('v2 http createField (e2e)', () => { } }); + it('persists aiConfig when creating field', async () => { + const fieldId = createFieldId(); + const aiConfig = { + type: 'summary', + modelKey: 'openai@gpt-4o@gpt', + sourceFieldId: tablePrimaryFieldId, + }; + + const response = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId, + field: { + id: fieldId, + type: 'singleLineText', + name: 'AI Summary', + aiConfig, + }, + }), + }); + + expect(response.status).toBe(200); + const raw = await response.json(); + const parsed = createFieldOkResponseSchema.safeParse(raw); + expect(parsed.success).toBe(true); + + const row = await ctx.testContainer.db + .selectFrom('field') + .select(['id', 'ai_config']) + .where('id', '=', fieldId) + .executeTakeFirst(); + + expect(row?.id).toBe(fieldId); + expect(JSON.parse(row?.ai_config ?? 'null')).toEqual(aiConfig); + }); + + it('creates search index for new searchable field when table search indexing is enabled', async () => { + const trgmAvailable = await sql<{ available: boolean }>` + SELECT EXISTS ( + SELECT 1 + FROM pg_opclass + WHERE opcname = 'gin_trgm_ops' + ) AS available + `.execute(ctx.testContainer.db); + + if (!trgmAvailable.rows[0]?.available) { + await sql + .raw('CREATE EXTENSION IF NOT EXISTS pg_trgm') + .execute(ctx.testContainer.db) + .catch(() => undefined); + } + + const trgmEnabled = await sql<{ available: boolean }>` + SELECT EXISTS ( + SELECT 1 + FROM pg_opclass + WHERE opcname = 'gin_trgm_ops' + ) AS available + `.execute(ctx.testContainer.db); + + if (!trgmEnabled.rows[0]?.available) { + return; + } + + const bootstrapIndexName = `idx_trgm_${tableId}_bootstrap`; + await sql + .raw( + `CREATE INDEX IF NOT EXISTS "${bootstrapIndexName}" ON "${ctx.baseId}"."${tableId}" USING gin (("${tablePrimaryDbFieldName}") gin_trgm_ops)` + ) + .execute(ctx.testContainer.db); + + const fieldId = createFieldId(); + const response = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId, + field: { + id: fieldId, + type: 'singleLineText', + name: 'Searchable Field', + }, + }), + }); + const raw = await response.json(); + expect(response.status).toBe(200); + const parsed = createFieldOkResponseSchema.safeParse(raw); + expect(parsed.success).toBe(true); + if (!parsed.success || !parsed.data.ok) { + return; + } + + const created = parsed.data.data.table.fields.find((field) => field.id === fieldId); + expect(created).toBeTruthy(); + if (!created) { + return; + } + if (typeof created.dbFieldName !== 'string') { + return; + } + + const expectedIndexName = getSearchIndexName(tableId, created.dbFieldName, created.id); + const indexRows = await sql<{ indexname: string }>` + SELECT indexname + FROM pg_indexes + WHERE schemaname = ${ctx.baseId} + AND tablename = ${tableId} + AND indexname = ${expectedIndexName} + `.execute(ctx.testContainer.db); + + expect(indexRows.rows.some((row) => row.indexname === expectedIndexName)).toBe(true); + }); + it('creates all field types with configured options', async () => { const numberFieldId = createFieldId(); const formulaFieldId = createFieldId(); @@ -605,6 +742,196 @@ describe('v2 http createField (e2e)', () => { expect(symmetricLinks).toHaveLength(0); } }); + + it('does not persist same-base baseId onto symmetric link fields', async () => { + const linkFieldId = createFieldId(); + const response = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId, + field: { + type: 'link', + id: linkFieldId, + name: `Same Base Link ${linkFieldId}`, + options: { + baseId: ctx.baseId, + relationship: 'manyOne', + foreignTableId, + lookupFieldId: foreignPrimaryFieldId, + }, + }, + }), + }); + + const rawBody = await response.json(); + if (response.status !== 200) { + throw new Error(`CreateField failed for same-base link: ${JSON.stringify(rawBody)}`); + } + const parsed = createFieldOkResponseSchema.safeParse(rawBody); + expect(parsed.success).toBe(true); + if (!parsed.success || !parsed.data.ok) return; + + const created = parsed.data.data.table.fields.find((field) => field.id === linkFieldId); + expect(created).toBeTruthy(); + if (!created || created.type !== 'link') return; + + const symmetricFieldId = created.options.symmetricFieldId; + expect(typeof symmetricFieldId).toBe('string'); + if (typeof symmetricFieldId !== 'string') return; + + const foreignTable = await getTableById(foreignTableId); + const symmetric = foreignTable.fields.find((field) => field.id === symmetricFieldId); + expect(symmetric).toBeTruthy(); + if (!symmetric || symmetric.type !== 'link') return; + + expect(symmetric.options.baseId).toBeUndefined(); + }); + + it('accepts explicit link db config and keeps it', async () => { + const hostTable = await createTable({ + baseId: ctx.baseId, + name: 'Configured Link Host', + fields: [{ type: 'singleLineText', name: 'Name' }], + }); + const foreignTable = await createTable({ + baseId: ctx.baseId, + name: 'Configured Link Foreign', + fields: [{ type: 'singleLineText', name: 'Name' }], + }); + + try { + const foreignPrimary = foreignTable.fields.find((field) => field.isPrimary); + expect(foreignPrimary).toBeTruthy(); + if (!foreignPrimary) return; + + const linkFieldId = createFieldId(); + const symmetricFieldId = createFieldId(); + const customJunctionTable = `junction_cfg_${linkFieldId.slice(-4)}_${symmetricFieldId.slice(-4)}`; + const customFkHostTableName = `${ctx.baseId}.${customJunctionTable}`; + const selfKeyName = `__fk_${symmetricFieldId}`; + const foreignKeyName = `__fk_${linkFieldId}`; + + const response = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'link', + id: linkFieldId, + name: `Configured Link ${linkFieldId}`, + options: { + relationship: 'manyMany', + foreignTableId: foreignTable.id, + lookupFieldId: foreignPrimary.id, + symmetricFieldId, + fkHostTableName: customFkHostTableName, + selfKeyName, + foreignKeyName, + }, + }, + }), + }); + + const rawBody = await response.json(); + if (response.status !== 200) { + throw new Error(`CreateField failed for configured link: ${JSON.stringify(rawBody)}`); + } + const parsed = createFieldOkResponseSchema.safeParse(rawBody); + expect(parsed.success).toBe(true); + if (!parsed.success || !parsed.data.ok) return; + + const created = parsed.data.data.table.fields.find((field) => field.id === linkFieldId); + expect(created).toBeTruthy(); + if (!created || created.type !== 'link') return; + expect(created.options.fkHostTableName).toBe(customFkHostTableName); + expect(created.options.selfKeyName).toBe(selfKeyName); + expect(created.options.foreignKeyName).toBe(foreignKeyName); + + const hostRecord = await ctx.createRecord(hostTable.id, { Name: 'host-1' }); + const foreignRecord = await ctx.createRecord(foreignTable.id, { Name: 'foreign-1' }); + await ctx.updateRecord(hostTable.id, hostRecord.id, { + [linkFieldId]: [{ id: foreignRecord.id }], + }); + + const records = await ctx.listRecords(hostTable.id); + expect(records[0]?.fields?.[linkFieldId]).toEqual([ + { id: foreignRecord.id, title: 'foreign-1' }, + ]); + } finally { + await ctx.deleteTable(hostTable.id).catch(() => undefined); + await ctx.deleteTable(foreignTable.id).catch(() => undefined); + } + }); + + it('defaults lookupFieldId to foreign primary when omitted', async () => { + const hostTable = await createTable({ + baseId: ctx.baseId, + name: 'Default Lookup Host', + fields: [{ type: 'singleLineText', name: 'Name' }], + }); + const foreignTable = await createTable({ + baseId: ctx.baseId, + name: 'Default Lookup Foreign', + fields: [{ type: 'singleLineText', name: 'Title' }], + }); + + try { + const hostPrimary = hostTable.fields.find((field) => field.isPrimary); + const foreignPrimary = foreignTable.fields.find((field) => field.isPrimary); + expect(hostPrimary).toBeTruthy(); + expect(foreignPrimary).toBeTruthy(); + if (!hostPrimary || !foreignPrimary) return; + + const linkFieldId = createFieldId(); + const response = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId: hostTable.id, + field: { + type: 'link', + id: linkFieldId, + name: `Lookup Default ${linkFieldId}`, + options: { + relationship: 'manyMany', + foreignTableId: foreignTable.id, + }, + }, + }), + }); + + const rawBody = await response.json(); + if (response.status !== 200) { + throw new Error(`CreateField failed for default lookup: ${JSON.stringify(rawBody)}`); + } + const parsed = createFieldOkResponseSchema.safeParse(rawBody); + expect(parsed.success).toBe(true); + if (!parsed.success || !parsed.data.ok) return; + + const created = parsed.data.data.table.fields.find((field) => field.id === linkFieldId); + expect(created).toBeTruthy(); + if (!created || created.type !== 'link') return; + expect(created.options.lookupFieldId).toBe(foreignPrimary.id); + + const symmetricFieldId = created.options.symmetricFieldId; + expect(typeof symmetricFieldId).toBe('string'); + if (typeof symmetricFieldId !== 'string') return; + + const foreignTableNext = await getTableById(foreignTable.id); + const symmetric = foreignTableNext.fields.find((field) => field.id === symmetricFieldId); + expect(symmetric).toBeTruthy(); + if (!symmetric || symmetric.type !== 'link') return; + expect(symmetric.options.lookupFieldId).toBe(hostPrimary.id); + } finally { + await ctx.deleteTable(hostTable.id).catch(() => undefined); + await ctx.deleteTable(foreignTable.id).catch(() => undefined); + } + }); }); describe('rollup fields', () => { @@ -1103,16 +1430,6 @@ describe('v2 http createField (e2e)', () => { }); const rawBody = await response.json(); - if (!entry.expectOk) { - expect(response.status).not.toBe(200); - const errorParsed = createFieldErrorResponseSchema.safeParse(rawBody); - expect(errorParsed.success).toBe(true); - if (!errorParsed.success) return; - expect(errorParsed.data.ok).toBe(false); - expect(errorParsed.data.error.message).toContain('Invalid RollupExpression'); - return; - } - if (response.status !== 200) { throw new Error(`CreateField failed for rollup: ${JSON.stringify(rawBody)}`); } @@ -1126,6 +1443,11 @@ describe('v2 http createField (e2e)', () => { if (!created || created.type !== 'rollup') return; expect(created.options.expression).toBe(entry.expression); expect(created.config.lookupFieldId).toBe(entry.lookupFieldId); + if (!entry.expectOk) { + expect(created.hasError).toBe(true); + return; + } + expect(created.hasError).toBeUndefined(); }); }); diff --git a/packages/v2/e2e/src/duplicateField.e2e.spec.ts b/packages/v2/e2e/src/duplicateField.e2e.spec.ts index 42ff53d73..46d3f9242 100644 --- a/packages/v2/e2e/src/duplicateField.e2e.spec.ts +++ b/packages/v2/e2e/src/duplicateField.e2e.spec.ts @@ -1,4 +1,5 @@ -import { beforeAll, describe, it } from 'vitest'; +import { duplicateFieldOkResponseSchema } from '@teable/v2-contract-http'; +import { beforeAll, describe, expect, it } from 'vitest'; import { getSharedTestContext, type SharedTestContext } from './shared/globalTestContext'; type DuplicateFieldCase = { @@ -277,6 +278,284 @@ describe('duplicateField', () => { ctx = await getSharedTestContext(); }); + it('respects viewId and updates duplicated field order in target view meta', async () => { + const table = await ctx.createTable({ + baseId: ctx.baseId, + name: `DupFieldViewOrder-${Date.now()}`, + fields: [ + { type: 'singleLineText', name: 'Name', isPrimary: true }, + { type: 'singleLineText', name: 'Source' }, + { type: 'singleLineText', name: 'Tail' }, + ], + }); + + const targetView = table.views[0]; + const sourceField = table.fields.find((field) => field.name === 'Source'); + const tailField = table.fields.find((field) => field.name === 'Tail'); + + expect(targetView).toBeTruthy(); + expect(sourceField).toBeTruthy(); + expect(tailField).toBeTruthy(); + if (!targetView || !sourceField || !tailField) return; + + const response = await fetch(`${ctx.baseUrl}/tables/duplicateField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId: table.id, + fieldId: sourceField.id, + includeRecordValues: true, + newFieldName: 'Source (copy)', + viewId: targetView.id, + }), + }); + + expect(response.status).toBe(200); + const raw = await response.json(); + const parsed = duplicateFieldOkResponseSchema.safeParse(raw); + expect(parsed.success).toBe(true); + if (!parsed.success || !parsed.data.ok) return; + + const duplicatedFieldId = parsed.data.data.newFieldId; + const latestTable = await ctx.getTableById(table.id); + const latestView = latestTable.views.find((view) => view.id === targetView.id); + expect(latestView).toBeTruthy(); + if (!latestView) return; + + const sourceOrder = latestView.columnMeta[sourceField.id]?.order; + const tailOrder = latestView.columnMeta[tailField.id]?.order; + const duplicatedOrder = latestView.columnMeta[duplicatedFieldId]?.order; + + expect(typeof sourceOrder).toBe('number'); + expect(typeof tailOrder).toBe('number'); + expect(typeof duplicatedOrder).toBe('number'); + expect((duplicatedOrder as number) > (sourceOrder as number)).toBe(true); + expect((duplicatedOrder as number) < (tailOrder as number)).toBe(true); + + await ctx.deleteTable(table.id); + }); + + it('duplicates all field types with unique dbFieldName', async () => { + let hostTableId: string | undefined; + let foreignTableId: string | undefined; + + const condition = (fieldId: string, value: string) => ({ + filter: { + conjunction: 'and' as const, + filterSet: [{ fieldId, operator: 'is', value }], + }, + }); + + const duplicateAndAssert = async (fieldId: string, baseName: string) => { + const before = await ctx.getTableById(hostTableId!); + const source = before.fields.find((f) => f.id === fieldId); + expect(source).toBeTruthy(); + expect(source?.dbFieldName).toBeTruthy(); + + const response = await fetch(`${ctx.baseUrl}/tables/duplicateField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId: hostTableId, + fieldId, + includeRecordValues: true, + newFieldName: `${baseName}-copy-${Date.now()}`, + }), + }); + + expect(response.status).toBe(200); + const raw = await response.json(); + const parsed = duplicateFieldOkResponseSchema.safeParse(raw); + expect(parsed.success).toBe(true); + if (!parsed.success || !parsed.data.ok) return; + + const after = await ctx.getTableById(hostTableId!); + const duplicated = after.fields.find((f) => f.id === parsed.data.data.newFieldId); + expect(duplicated).toBeTruthy(); + expect(duplicated?.dbFieldName).toBeTruthy(); + expect(duplicated?.dbFieldName).not.toBe(source?.dbFieldName); + }; + + try { + const foreignStatusFieldId = `fld${'a'.repeat(16)}`; + const foreignAmountFieldId = `fld${'b'.repeat(16)}`; + const foreignTable = await ctx.createTable({ + baseId: ctx.baseId, + name: `DupFieldForeign-${Date.now()}`, + fields: [ + { type: 'singleLineText', name: 'Foreign Name', isPrimary: true }, + { type: 'singleLineText', id: foreignStatusFieldId, name: 'Status' }, + { type: 'number', id: foreignAmountFieldId, name: 'Amount' }, + ], + }); + foreignTableId = foreignTable.id; + const foreignPrimaryField = foreignTable.fields.find((f) => f.isPrimary); + if (!foreignPrimaryField) throw new Error('Missing foreign primary field'); + + const hostTable = await ctx.createTable({ + baseId: ctx.baseId, + name: `DupFieldHost-${Date.now()}`, + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + }); + hostTableId = hostTable.id; + + const createAndGetId = async ( + field: Parameters[0]['field'], + name: string + ) => { + const updated = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTableId!, + field, + }); + const created = updated.fields.find((f) => f.name === name); + if (!created) throw new Error(`Missing created field: ${name}`); + return created.id; + }; + + const linkFieldId = await createAndGetId( + { + type: 'link', + name: 'Link Field', + options: { + relationship: 'manyMany', + foreignTableId: foreignTableId!, + lookupFieldId: foreignPrimaryField.id, + }, + }, + 'Link Field' + ); + + const numberFieldId = await createAndGetId( + { type: 'number', name: 'Number Field' }, + 'Number Field' + ); + + const allTypeFieldIds = [ + await createAndGetId({ type: 'singleLineText', name: 'Text Field' }, 'Text Field'), + await createAndGetId({ type: 'longText', name: 'Long Text Field' }, 'Long Text Field'), + numberFieldId, + await createAndGetId({ type: 'rating', name: 'Rating Field' }, 'Rating Field'), + await createAndGetId({ type: 'checkbox', name: 'Checkbox Field' }, 'Checkbox Field'), + await createAndGetId({ type: 'date', name: 'Date Field' }, 'Date Field'), + await createAndGetId( + { + type: 'singleSelect', + name: 'Single Select Field', + options: { choices: [{ name: 'A', color: 'blue' }] }, + }, + 'Single Select Field' + ), + await createAndGetId( + { + type: 'multipleSelect', + name: 'Multi Select Field', + options: { choices: [{ name: 'A', color: 'blue' }] }, + }, + 'Multi Select Field' + ), + await createAndGetId( + { type: 'user', name: 'User Field', options: { isMultiple: true, shouldNotify: false } }, + 'User Field' + ), + await createAndGetId({ type: 'attachment', name: 'Attachment Field' }, 'Attachment Field'), + await createAndGetId( + { + type: 'formula', + name: 'Formula Field', + options: { expression: `{${numberFieldId}} + 1` }, + }, + 'Formula Field' + ), + await createAndGetId( + { + type: 'lookup', + name: 'Lookup Field', + options: { + linkFieldId, + foreignTableId: foreignTableId!, + lookupFieldId: foreignPrimaryField.id, + }, + }, + 'Lookup Field' + ), + await createAndGetId( + { + type: 'rollup', + name: 'Rollup Field', + options: { expression: 'sum({values})' }, + config: { + linkFieldId, + foreignTableId: foreignTableId!, + lookupFieldId: foreignAmountFieldId, + }, + }, + 'Rollup Field' + ), + await createAndGetId( + { + type: 'conditionalLookup', + name: 'Conditional Lookup Field', + options: { + foreignTableId: foreignTableId!, + lookupFieldId: foreignPrimaryField.id, + condition: condition(foreignStatusFieldId, 'Active'), + }, + }, + 'Conditional Lookup Field' + ), + await createAndGetId( + { + type: 'conditionalRollup', + name: 'Conditional Rollup Field', + options: { expression: 'sum({values})' }, + config: { + foreignTableId: foreignTableId!, + lookupFieldId: foreignAmountFieldId, + condition: condition(foreignStatusFieldId, 'Active'), + }, + }, + 'Conditional Rollup Field' + ), + await createAndGetId( + { type: 'createdTime', name: 'Created Time Field' }, + 'Created Time Field' + ), + await createAndGetId( + { type: 'lastModifiedTime', name: 'Last Modified Time Field' }, + 'Last Modified Time Field' + ), + await createAndGetId({ type: 'createdBy', name: 'Created By Field' }, 'Created By Field'), + await createAndGetId( + { type: 'lastModifiedBy', name: 'Last Modified By Field' }, + 'Last Modified By Field' + ), + await createAndGetId( + { type: 'autoNumber', name: 'Auto Number Field' }, + 'Auto Number Field' + ), + await createAndGetId( + { type: 'button', name: 'Button Field', options: { label: 'Click', color: 'teal' } }, + 'Button Field' + ), + linkFieldId, + ]; + + for (const fieldId of allTypeFieldIds) { + await duplicateAndAssert(fieldId, `dup-${fieldId}`); + } + } finally { + if (hostTableId) { + await ctx.deleteTable(hostTableId).catch(() => undefined); + } + if (foreignTableId) { + await ctx.deleteTable(foreignTableId).catch(() => undefined); + } + } + }); + describe.each(duplicateFieldCases)('duplicate field with values: $label', (caseInfo) => { it.todo(`includeRecordValues=true should copy values; setup: ${caseInfo.setupNotes}`); }); diff --git a/packages/v2/e2e/src/formula.e2e.spec.ts b/packages/v2/e2e/src/formula.e2e.spec.ts index d9d7e3bb7..fb9600a72 100644 --- a/packages/v2/e2e/src/formula.e2e.spec.ts +++ b/packages/v2/e2e/src/formula.e2e.spec.ts @@ -1529,6 +1529,106 @@ describe('v2 http formula (e2e)', () => { expect(record.fields[formulaFieldId]).toBe(expectedYear); }); + /** + * Scenario:Formula references created time on record create + * Formula:DATETIME_DIFF(NOW(), {createdTimeField}, "day") + * Expect: newly inserted record evaluates to zero days + */ + it('should create formula referencing created time on insert - DATETIME_DIFF(NOW(), {createdTimeField}, "day")', async () => { + const createTableResponse = await fetch(`${ctx.baseUrl}/tables/create`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + name: uniqueName('Created Time Age Formula Test'), + fields: [{ type: 'singleLineText', name: 'Name', isPrimary: true }], + views: [{ type: 'grid' }], + }), + }); + const tableRaw = await createTableResponse.json(); + const tableParsed = createTableOkResponseSchema.safeParse(tableRaw); + expect(tableParsed.success).toBe(true); + if (!tableParsed.success || !tableParsed.data.ok) return; + + const table = tableParsed.data.data.table; + const primaryFieldId = table.fields.find((f) => f.isPrimary)?.id ?? ''; + + const createCreatedTimeResponse = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId: table.id, + field: { + type: 'createdTime', + name: 'Created Time', + }, + }), + }); + expect(createCreatedTimeResponse.status).toBe(200); + const createdTimeRaw = await createCreatedTimeResponse.json(); + const createdTimeParsed = createFieldOkResponseSchema.safeParse(createdTimeRaw); + expect(createdTimeParsed.success).toBe(true); + if (!createdTimeParsed.success || !createdTimeParsed.data.ok) return; + + const createdTimeFieldId = + createdTimeParsed.data.data.table.fields.find((f) => f.type === 'createdTime')?.id ?? ''; + + const createFormulaResponse = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId: table.id, + field: { + type: 'formula', + name: 'CreatedAgeDays', + options: { + expression: `DATETIME_DIFF(NOW(), {${createdTimeFieldId}}, "day")`, + timeZone: 'utc', + }, + }, + }), + }); + if (createFormulaResponse.status !== 200) { + const errorText = await createFormulaResponse.text(); + throw new Error(`Create formula failed: ${errorText}`); + } + const formulaRaw = await createFormulaResponse.json(); + const formulaParsed = createFieldOkResponseSchema.safeParse(formulaRaw); + expect(formulaParsed.success).toBe(true); + if (!formulaParsed.success || !formulaParsed.data.ok) return; + + const formulaFieldId = + formulaParsed.data.data.table.fields.find((f) => f.name === 'CreatedAgeDays')?.id ?? ''; + + const createRecordResponse = await fetch(`${ctx.baseUrl}/tables/createRecord`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + tableId: table.id, + fields: { + [primaryFieldId]: 'Row 1', + }, + }), + }); + expect(createRecordResponse.status).toBe(201); + const recordRaw = await createRecordResponse.json(); + const recordParsed = createRecordOkResponseSchema.safeParse(recordRaw); + expect(recordParsed.success).toBe(true); + if (!recordParsed.success || !recordParsed.data.ok) return; + const recordId = recordParsed.data.data.record.id; + + await processOutbox(); + + const records = await listRecords(table.id); + const record = records.find((r) => r.id === recordId); + expect(record).toBeDefined(); + if (!record) return; + + expect(record.fields[formulaFieldId]).toBe(0); + }); + /** * Scenario:Formula references last modified time field * Formula:DATETIME_FORMAT({lastModifiedTimeField}, "YYYY-MM-DD") @@ -1923,7 +2023,7 @@ describe('v2 http formula (e2e)', () => { /** * Scenario: use SUBSTITUTE with number field (auto string coercion) * Formula:SUBSTITUTE({numberField}, "0", "X") - * Expect: coerces number to string before substitution + * Expect: coerces number to raw string before substitution */ it('should substitute numeric field as text - SUBSTITUTE({numberField}, "0", "X")', async () => { const createTableResponse = await fetch(`${ctx.baseUrl}/tables/create`, { @@ -1998,7 +2098,7 @@ describe('v2 http formula (e2e)', () => { expect(record).toBeDefined(); if (!record) return; - expect(record.fields[formulaFieldId]).toBe('1XXX.XX'); + expect(record.fields[formulaFieldId]).toBe('1XXX'); }); /** @@ -5589,7 +5689,7 @@ describe('v2 http formula (e2e)', () => { /** * Scenario:T function * Formula:T({numberField}) - * Expect: returns text if input is text, otherwise empty string + * Expect: returns text representation */ it('should convert to text or empty - T({numberField})', async () => { const createTableResponse = await fetch(`${ctx.baseUrl}/tables/create`, { @@ -5661,7 +5761,7 @@ describe('v2 http formula (e2e)', () => { expect(record).toBeDefined(); if (!record) return; - expect(record.fields[formulaFieldId]).toBe(null); + expect(record.fields[formulaFieldId]).toBe('123'); }); /** @@ -7932,6 +8032,88 @@ describe('v2 http formula (e2e)', () => { expect(record.fields[formulaFieldId]).toBe(2); }); + /** + * Scenario:DATETIME_DIFF default unit + * Formula:DATETIME_DIFF({date1}, {date2}) + * Expect: defaults to day unit and keeps sign when end precedes start + */ + it('should get datetime diff with default unit - DATETIME_DIFF({date1}, {date2})', async () => { + const createTableResponse = await fetch(`${ctx.baseUrl}/tables/create`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + name: uniqueName('DATETIME_DIFF Default Unit Test'), + fields: [ + { type: 'singleLineText', name: 'Name', isPrimary: true }, + { type: 'date', name: 'Date1' }, + { type: 'date', name: 'Date2' }, + ], + views: [{ type: 'grid' }], + }), + }); + const tableRaw = await createTableResponse.json(); + const tableParsed = createTableOkResponseSchema.safeParse(tableRaw); + expect(tableParsed.success).toBe(true); + if (!tableParsed.success || !tableParsed.data.ok) return; + + const table = tableParsed.data.data.table; + const date1FieldId = table.fields.find((f) => f.name === 'Date1')?.id ?? ''; + const date2FieldId = table.fields.find((f) => f.name === 'Date2')?.id ?? ''; + + const createFieldResponse = await fetch(`${ctx.baseUrl}/tables/createField`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + baseId: ctx.baseId, + tableId: table.id, + field: { + type: 'formula', + name: 'DiffDaysDefault', + options: { expression: `DATETIME_DIFF({${date1FieldId}}, {${date2FieldId}})` }, + }, + }), + }); + expect(createFieldResponse.status).toBe(200); + const fieldRaw = await createFieldResponse.json(); + const fieldParsed = createFieldOkResponseSchema.safeParse(fieldRaw); + expect(fieldParsed.success).toBe(true); + if (!fieldParsed.success || !fieldParsed.data.ok) return; + + const formulaFieldId = + fieldParsed.data.data.table.fields.find((f) => f.name === 'DiffDaysDefault')?.id ?? ''; + + const createRecordResponse = await fetch(`${ctx.baseUrl}/tables/createRecord`, { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify({ + tableId: table.id, + fields: { + [date1FieldId]: '2024-01-03T00:00:00.000Z', + [date2FieldId]: '2024-01-01T00:00:00.000Z', + }, + }), + }); + expect(createRecordResponse.status).toBe(201); + const recordRaw = await createRecordResponse.json(); + const recordParsed = createRecordOkResponseSchema.safeParse(recordRaw); + expect(recordParsed.success).toBe(true); + if (!recordParsed.success || !recordParsed.data.ok) return; + const recordId = recordParsed.data.data.record.id; + + await processOutbox(); + + const records = await listRecords(table.id); + const record = records.find((r) => r.id === recordId); + expect(record).toBeDefined(); + if (!record) return; + + const diffValue = record.fields[formulaFieldId]; + expect(typeof diffValue).toBe('number'); + if (typeof diffValue !== 'number') return; + expect(diffValue).toBeCloseTo(2, 6); + }); + /** * Scenario:DATETIME_FORMAT function * Formula:DATETIME_FORMAT({dateField}, "YYYY-MM-DD") @@ -14509,8 +14691,8 @@ describe('v2 http formula (e2e)', () => { }), }); - // 3. Verify 500 error (invalid function causes parse error) - expect(createFieldResponse.status).toBe(500); + // 3. Verify 400 error (invalid function causes parse validation error) + expect(createFieldResponse.status).toBe(400); }); /** diff --git a/packages/v2/e2e/src/update-field/attachment/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/attachment/conversion/to-lookup.spec.ts index 9dccf2047..0d2037eaa 100644 --- a/packages/v2/e2e/src/update-field/attachment/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/attachment/conversion/to-lookup.spec.ts @@ -137,7 +137,7 @@ describe('update-field: attachment → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/checkbox/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/checkbox/conversion/to-lookup.spec.ts index 891086668..8e1b654da 100644 --- a/packages/v2/e2e/src/update-field/checkbox/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/checkbox/conversion/to-lookup.spec.ts @@ -120,7 +120,7 @@ describe('update-field: checkbox → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/computed/record-value-seeding.spec.ts b/packages/v2/e2e/src/update-field/computed/record-value-seeding.spec.ts index 99ac876ee..15d758a84 100644 --- a/packages/v2/e2e/src/update-field/computed/record-value-seeding.spec.ts +++ b/packages/v2/e2e/src/update-field/computed/record-value-seeding.spec.ts @@ -281,23 +281,26 @@ describe('update-field: record value seeding after property changes', () => { [hostLinkFieldId]: [{ id: rec1.id }, { id: rec2.id }, { id: rec3.id }], }); - await expect( - ctx.createField({ - baseId: ctx.baseId, - tableId: hostTableId, - field: { - type: 'rollup', - id: hostRollupFieldId, - name: 'Amount Sum', - options: { expression: 'sum({values})' }, - config: { - linkFieldId: hostLinkFieldId, - foreignTableId: sourceTableId, - lookupFieldId: sourceAmountFieldId, - }, + const createdTable = await ctx.createField({ + baseId: ctx.baseId, + tableId: hostTableId, + field: { + type: 'rollup', + id: hostRollupFieldId, + name: 'Amount Sum', + options: { expression: 'sum({values})' }, + config: { + linkFieldId: hostLinkFieldId, + foreignTableId: sourceTableId, + lookupFieldId: sourceAmountFieldId, }, - }) - ).rejects.toThrow('Invalid RollupExpression for RollupField value type'); + }, + }); + + const createdRollupField = createdTable.fields.find( + (field) => field.id === hostRollupFieldId + ); + expect(createdRollupField?.hasError).toBe(true); } finally { await deleteTableSafe(ctx, hostTableId); await deleteTableSafe(ctx, sourceTableId); diff --git a/packages/v2/e2e/src/update-field/date/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/date/conversion/to-lookup.spec.ts index 12f31059a..08b9d619d 100644 --- a/packages/v2/e2e/src/update-field/date/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/date/conversion/to-lookup.spec.ts @@ -135,7 +135,7 @@ describe('update-field: date → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/longText/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/longText/conversion/to-lookup.spec.ts index 5251a0f74..88cd72436 100644 --- a/packages/v2/e2e/src/update-field/longText/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/longText/conversion/to-lookup.spec.ts @@ -120,7 +120,7 @@ describe('update-field: longText → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/multipleSelect/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/multipleSelect/conversion/to-lookup.spec.ts index 8b8932ef0..c15398c6d 100644 --- a/packages/v2/e2e/src/update-field/multipleSelect/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/multipleSelect/conversion/to-lookup.spec.ts @@ -126,7 +126,7 @@ describe('update-field: multipleSelect → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/number/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/number/conversion/to-lookup.spec.ts index 2f388857c..58a37e8db 100644 --- a/packages/v2/e2e/src/update-field/number/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/number/conversion/to-lookup.spec.ts @@ -120,7 +120,7 @@ describe('update-field: number → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/rating/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/rating/conversion/to-lookup.spec.ts index 3e42882e3..72fe81d22 100644 --- a/packages/v2/e2e/src/update-field/rating/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/rating/conversion/to-lookup.spec.ts @@ -121,7 +121,7 @@ describe('update-field: rating → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/singleLineText/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/singleLineText/conversion/to-lookup.spec.ts index deeb296e7..732f50b74 100644 --- a/packages/v2/e2e/src/update-field/singleLineText/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/singleLineText/conversion/to-lookup.spec.ts @@ -120,7 +120,7 @@ describe('update-field: singleLineText → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, @@ -201,7 +201,7 @@ describe('update-field: singleLineText → lookup conversion', () => { expect(updatedField?.isMultipleCellValue).not.toBe(true); expect(fieldStorageRow.db_field_type).toBe('TEXT'); expect(fieldStorageRow.is_multiple_cell_value).toBe(false); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId: manyOneLinkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/singleSelect/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/singleSelect/conversion/to-lookup.spec.ts index b451be86f..e21f968bb 100644 --- a/packages/v2/e2e/src/update-field/singleSelect/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/singleSelect/conversion/to-lookup.spec.ts @@ -126,7 +126,7 @@ describe('update-field: singleSelect → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/e2e/src/update-field/user/conversion/to-lookup.spec.ts b/packages/v2/e2e/src/update-field/user/conversion/to-lookup.spec.ts index 535b3f932..6050e06e1 100644 --- a/packages/v2/e2e/src/update-field/user/conversion/to-lookup.spec.ts +++ b/packages/v2/e2e/src/update-field/user/conversion/to-lookup.spec.ts @@ -124,7 +124,7 @@ describe('update-field: user → lookup conversion', () => { } | undefined; expect(updatedField?.isLookup).toBe(true); - expect(updatedField?.lookupOptions).toEqual({ + expect(updatedField?.lookupOptions).toMatchObject({ linkFieldId, foreignTableId, lookupFieldId: foreignPrimaryFieldId, diff --git a/packages/v2/formula-sql-pg/src/DatetimeDiffParity.spec.ts b/packages/v2/formula-sql-pg/src/DatetimeDiffParity.spec.ts new file mode 100644 index 000000000..a6a4ef38b --- /dev/null +++ b/packages/v2/formula-sql-pg/src/DatetimeDiffParity.spec.ts @@ -0,0 +1,75 @@ +import type { IV2NodeTestContainer } from '@teable/v2-container-node-test'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; + +import { + buildFormulaSnapshotContext, + createFormulaTestContainer, + createFormulaTestTable, + type FormulaTestTable, +} from './testkit/FormulaSqlPgTestkit'; + +const parseNumericResult = (value: string | null): number => { + expect(value).not.toBeNull(); + const parsed = Number(value); + expect(Number.isFinite(parsed)).toBe(true); + return parsed; +}; + +describe('DATETIME_DIFF parity', () => { + let container: IV2NodeTestContainer; + let testTable: FormulaTestTable; + + beforeAll(async () => { + container = await createFormulaTestContainer(); + testTable = await createFormulaTestTable(container, [ + { + name: 'DiffDefaultUnit', + expression: 'DATETIME_DIFF("2024-01-03T00:00:00Z", "2024-01-01T00:00:00Z")', + }, + { + name: 'DiffExplicitDay', + expression: 'DATETIME_DIFF("2024-01-03T00:00:00Z", "2024-01-01T00:00:00Z", "day")', + }, + { + name: 'DiffSubSecondPositiveDay', + expression: 'DATETIME_DIFF("2024-01-01T00:00:00.500Z", "2024-01-01T00:00:00.000Z", "day")', + }, + { + name: 'DiffSubSecondNegativeDay', + expression: 'DATETIME_DIFF("2024-01-01T00:00:00.000Z", "2024-01-01T00:00:00.500Z", "day")', + }, + ]); + }); + + afterAll(async () => { + await container.dispose(); + }); + + it('defaults DATETIME_DIFF unit to day when omitted', async () => { + const [defaultContext, explicitDayContext] = await Promise.all([ + buildFormulaSnapshotContext(testTable, 'DiffDefaultUnit'), + buildFormulaSnapshotContext(testTable, 'DiffExplicitDay'), + ]); + + expect(defaultContext.sql).toContain('/ 86400'); + + const defaultValue = parseNumericResult(defaultContext.result); + const explicitDayValue = parseNumericResult(explicitDayContext.result); + + expect(defaultValue).toBeCloseTo(2, 10); + expect(defaultValue).toBeCloseTo(explicitDayValue, 10); + }); + + it('returns zero for day unit when datetime difference is sub-second', async () => { + const [positiveContext, negativeContext] = await Promise.all([ + buildFormulaSnapshotContext(testTable, 'DiffSubSecondPositiveDay'), + buildFormulaSnapshotContext(testTable, 'DiffSubSecondNegativeDay'), + ]); + + expect(positiveContext.sql).toContain('ABS(('); + expect(positiveContext.sql).toContain('< 1 THEN 0::double precision'); + + expect(parseNumericResult(positiveContext.result)).toBeCloseTo(0, 10); + expect(parseNumericResult(negativeContext.result)).toBeCloseTo(0, 10); + }); +}); diff --git a/packages/v2/formula-sql-pg/src/FormulaSqlPgExpressionBuilder.ts b/packages/v2/formula-sql-pg/src/FormulaSqlPgExpressionBuilder.ts index b0c98547c..1d9595ea7 100644 --- a/packages/v2/formula-sql-pg/src/FormulaSqlPgExpressionBuilder.ts +++ b/packages/v2/formula-sql-pg/src/FormulaSqlPgExpressionBuilder.ts @@ -33,7 +33,16 @@ import { } from './SqlExpression'; import { mapTimeZoneToPg } from './TimeZonePgMapping'; -type DateAddUnit = 'year' | 'quarter' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second'; +type DateAddUnit = + | 'millisecond' + | 'year' + | 'quarter' + | 'month' + | 'week' + | 'day' + | 'hour' + | 'minute' + | 'second'; type DatetimeDiffUnit = | 'millisecond' | 'second' @@ -44,9 +53,12 @@ type DatetimeDiffUnit = | 'month' | 'quarter' | 'year'; -type IsSameUnit = 'year' | 'month' | 'day'; +type IsSameUnit = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second'; export const DATE_ADD_UNIT_ALIASES: Record = { + millisecond: 'millisecond', + milliseconds: 'millisecond', + ms: 'millisecond', year: 'year', years: 'year', quarter: 'quarter', @@ -61,19 +73,36 @@ export const DATE_ADD_UNIT_ALIASES: Record = { hours: 'hour', minute: 'minute', minutes: 'minute', + min: 'minute', + mins: 'minute', second: 'second', seconds: 'second', + s: 'second', + sec: 'second', + secs: 'second', + h: 'hour', + hr: 'hour', + hrs: 'hour', }; export const DATETIME_DIFF_UNIT_ALIASES: Record = { millisecond: 'millisecond', milliseconds: 'millisecond', + ms: 'millisecond', second: 'second', seconds: 'second', + s: 'second', + sec: 'second', + secs: 'second', minute: 'minute', minutes: 'minute', + min: 'minute', + mins: 'minute', hour: 'hour', hours: 'hour', + h: 'hour', + hr: 'hour', + hrs: 'hour', day: 'day', days: 'day', week: 'week', @@ -91,8 +120,24 @@ export const IS_SAME_UNIT_ALIASES: Record = { years: 'year', month: 'month', months: 'month', + week: 'week', + weeks: 'week', day: 'day', days: 'day', + hour: 'hour', + hours: 'hour', + h: 'hour', + hr: 'hour', + hrs: 'hour', + minute: 'minute', + minutes: 'minute', + min: 'minute', + mins: 'minute', + second: 'second', + seconds: 'second', + s: 'second', + sec: 'second', + secs: 'second', }; const JSON_OBJECT_FIELD_TYPES = new Set(['button', 'link']); @@ -118,6 +163,7 @@ const NON_DATETIME_FIELD_TYPES = new Set([ ]); const DATE_ADD_INTERVALS: Record = { + millisecond: "INTERVAL '1 millisecond'", year: "INTERVAL '1 year'", quarter: "INTERVAL '3 month'", month: "INTERVAL '1 month'", @@ -928,8 +974,7 @@ export class FormulaSqlPgExpressionBuilder { ); } if (expr.storageKind === 'json') { - // For known JSON storage fields, use direct cast instead of safeJsonbWithStrategy - const jsonbValue = `(${expr.valueSql})::jsonb`; + const jsonbValue = `to_jsonb(${expr.valueSql})`; const valueSql = this.isStructuredJsonField(expr) ? this.buildJsonObjectText(jsonbValue) : extractJsonScalarText(jsonbValue); @@ -1626,6 +1671,11 @@ export class FormulaSqlPgExpressionBuilder { protected buildDateAddCaseSql(unitSql: string, dateSql: string, countSql: string): string { return `(CASE + WHEN ${unitSql} IN ('millisecond', 'milliseconds', 'ms') THEN ${this.buildDateAddSql( + 'millisecond', + dateSql, + countSql + )} WHEN ${unitSql} IN ('year', 'years') THEN ${this.buildDateAddSql('year', dateSql, countSql)} WHEN ${unitSql} IN ('quarter', 'quarters') THEN ${this.buildDateAddSql( 'quarter', @@ -1645,11 +1695,18 @@ export class FormulaSqlPgExpressionBuilder { dateSql, countSql )} + WHEN ${unitSql} IN ('min', 'mins') THEN ${this.buildDateAddSql('minute', dateSql, countSql)} WHEN ${unitSql} IN ('second', 'seconds') THEN ${this.buildDateAddSql( 'second', dateSql, countSql )} + WHEN ${unitSql} IN ('s', 'sec', 'secs') THEN ${this.buildDateAddSql( + 'second', + dateSql, + countSql + )} + WHEN ${unitSql} IN ('h', 'hr', 'hrs') THEN ${this.buildDateAddSql('hour', dateSql, countSql)} ELSE NULL::timestamptz END)`; } @@ -1661,19 +1718,24 @@ export class FormulaSqlPgExpressionBuilder { diffYears: string ): string { const sqlByUnit: Record = { - millisecond: `TRUNC((${diffSeconds}) * 1000)`, - second: `TRUNC((${diffSeconds}))`, - minute: `TRUNC((${diffSeconds}) / 60)`, - hour: `TRUNC((${diffSeconds}) / 3600)`, - day: `TRUNC((${diffSeconds}) / 86400)`, - week: `TRUNC((${diffSeconds}) / (86400 * 7))`, - month: `TRUNC(${diffMonths})`, - quarter: `TRUNC((${diffMonths}) / 3.0)`, - year: `TRUNC(${diffYears})`, + millisecond: `((${diffSeconds}) * 1000)`, + second: `((${diffSeconds}))`, + minute: `((${diffSeconds}) / 60)`, + hour: `((${diffSeconds}) / 3600)`, + day: this.buildDatetimeDiffDaySql(diffSeconds), + week: `((${diffSeconds}) / (86400 * 7))`, + month: `${diffMonths}`, + quarter: `((${diffMonths}) / 3.0)`, + year: `${diffYears}`, }; return sqlByUnit[unit]; } + protected buildDatetimeDiffDaySql(diffSeconds: string): string { + // Align with v1 behavior for fresh inserts where NOW() and created-time can differ by sub-second jitter. + return `(CASE WHEN ABS((${diffSeconds})) < 1 THEN 0::double precision ELSE ((${diffSeconds}) / 86400) END)`; + } + protected buildDatetimeDiffCaseSql( unitSql: string, diffSeconds: string, @@ -1681,15 +1743,15 @@ export class FormulaSqlPgExpressionBuilder { diffYears: string ): string { return `(CASE - WHEN ${unitSql} IN ('millisecond', 'milliseconds') THEN TRUNC((${diffSeconds}) * 1000) - WHEN ${unitSql} IN ('second', 'seconds') THEN TRUNC((${diffSeconds})) - WHEN ${unitSql} IN ('minute', 'minutes') THEN TRUNC((${diffSeconds}) / 60) - WHEN ${unitSql} IN ('hour', 'hours') THEN TRUNC((${diffSeconds}) / 3600) - WHEN ${unitSql} IN ('week', 'weeks') THEN TRUNC((${diffSeconds}) / (86400 * 7)) - WHEN ${unitSql} IN ('month', 'months') THEN TRUNC(${diffMonths}) - WHEN ${unitSql} IN ('quarter', 'quarters') THEN TRUNC((${diffMonths}) / 3.0) - WHEN ${unitSql} IN ('year', 'years') THEN TRUNC(${diffYears}) - WHEN ${unitSql} IN ('day', 'days') THEN TRUNC((${diffSeconds}) / 86400) + WHEN ${unitSql} IN ('millisecond', 'milliseconds', 'ms') THEN ((${diffSeconds}) * 1000) + WHEN ${unitSql} IN ('second', 'seconds', 's', 'sec', 'secs') THEN ((${diffSeconds})) + WHEN ${unitSql} IN ('minute', 'minutes', 'min', 'mins') THEN ((${diffSeconds}) / 60) + WHEN ${unitSql} IN ('hour', 'hours', 'h', 'hr', 'hrs') THEN ((${diffSeconds}) / 3600) + WHEN ${unitSql} IN ('week', 'weeks') THEN ((${diffSeconds}) / (86400 * 7)) + WHEN ${unitSql} IN ('month', 'months') THEN ${diffMonths} + WHEN ${unitSql} IN ('quarter', 'quarters') THEN ((${diffMonths}) / 3.0) + WHEN ${unitSql} IN ('year', 'years') THEN ${diffYears} + WHEN ${unitSql} IN ('day', 'days') THEN ${this.buildDatetimeDiffDaySql(diffSeconds)} ELSE NULL::double precision END)`; } @@ -1700,7 +1762,11 @@ export class FormulaSqlPgExpressionBuilder { const sqlByUnit: Record = { year: `DATE_TRUNC('year', ${left}) = DATE_TRUNC('year', ${right})`, month: `DATE_TRUNC('month', ${left}) = DATE_TRUNC('month', ${right})`, + week: `DATE_TRUNC('week', ${left}) = DATE_TRUNC('week', ${right})`, day: `DATE_TRUNC('day', ${left}) = DATE_TRUNC('day', ${right})`, + hour: `DATE_TRUNC('hour', ${left}) = DATE_TRUNC('hour', ${right})`, + minute: `DATE_TRUNC('minute', ${left}) = DATE_TRUNC('minute', ${right})`, + second: `DATE_TRUNC('second', ${left}) = DATE_TRUNC('second', ${right})`, }; return sqlByUnit[unit]; } @@ -1709,7 +1775,23 @@ export class FormulaSqlPgExpressionBuilder { return `(CASE WHEN ${unitSql} IN ('year', 'years') THEN ${this.buildIsSameSql('year', leftSql, rightSql)} WHEN ${unitSql} IN ('month', 'months') THEN ${this.buildIsSameSql('month', leftSql, rightSql)} + WHEN ${unitSql} IN ('week', 'weeks') THEN ${this.buildIsSameSql('week', leftSql, rightSql)} WHEN ${unitSql} IN ('day', 'days') THEN ${this.buildIsSameSql('day', leftSql, rightSql)} + WHEN ${unitSql} IN ('hour', 'hours', 'h', 'hr', 'hrs') THEN ${this.buildIsSameSql( + 'hour', + leftSql, + rightSql + )} + WHEN ${unitSql} IN ('minute', 'minutes', 'min', 'mins') THEN ${this.buildIsSameSql( + 'minute', + leftSql, + rightSql + )} + WHEN ${unitSql} IN ('second', 'seconds', 's', 'sec', 'secs') THEN ${this.buildIsSameSql( + 'second', + leftSql, + rightSql + )} ELSE NULL END)`; } @@ -1738,6 +1820,44 @@ export class FormulaSqlPgExpressionBuilder { return `(SELECT ${buildBody(ref)} FROM (SELECT ${valueSql} AS ${column}) AS ${tableAlias})`; } + protected coerceArrayElementToNumber( + arrayExpr: SqlExpr, + elementRef: string, + reason: string + ): SqlExpr { + const elemExpr = makeExpr( + extractJsonScalarText(elementRef), + arrayExpr.valueType ?? 'unknown', + false, + arrayExpr.errorConditionSql, + arrayExpr.errorMessageSql, + arrayExpr.field + ); + + // Fast path for numeric arrays (for example lookup) to avoid + // generating deeply nested regex guards for every element. + if (arrayExpr.valueType === 'number') { + const textSql = `(${elemExpr.valueSql})::text`; + const castable = this.typeValidation.isValidForType(textSql, 'numeric'); + const errorCondition = `(${elementRef} IS NOT NULL AND jsonb_typeof(${elementRef}) <> 'null' AND NOT (${castable}))`; + const valueSql = `(CASE + WHEN ${elementRef} IS NULL OR jsonb_typeof(${elementRef}) = 'null' THEN NULL::double precision + WHEN ${castable} THEN (${textSql})::double precision + ELSE NULL::double precision + END)`; + return makeExpr( + valueSql, + 'number', + false, + errorCondition, + buildErrorLiteral('TYPE', 'cannot_cast_to_number'), + arrayExpr.field + ); + } + + return this.coerceToNumber(elemExpr, reason); + } + protected vectorizeArrayScalar( arrayExpr: SqlExpr, scalarExpr: SqlExpr, @@ -1746,14 +1866,7 @@ export class FormulaSqlPgExpressionBuilder { ): SqlExpr { const normalizedArray = this.normalizeArrayExpr(arrayExpr); const scalarNumber = this.coerceToNumber(scalarExpr, reason); - const elemExpr = makeExpr( - extractJsonScalarText('elem'), - 'unknown', - false, - arrayExpr.errorConditionSql, - arrayExpr.errorMessageSql - ); - const elementNumber = this.coerceToNumber(elemExpr, reason); + const elementNumber = this.coerceArrayElementToNumber(arrayExpr, 'elem', reason); const elementErrorCondition = combineErrorConditions([elementNumber, scalarNumber]); const elementErrorMessage = buildErrorMessageSql( [elementNumber, scalarNumber], @@ -1782,14 +1895,7 @@ export class FormulaSqlPgExpressionBuilder { protected vectorizeUnaryNumeric(expr: SqlExpr, op: (valueSql: string) => string): SqlExpr { const normalizedArray = this.normalizeArrayExpr(expr); - const elemExpr = makeExpr( - extractJsonScalarText('elem'), - 'unknown', - false, - expr.errorConditionSql, - expr.errorMessageSql - ); - const elementNumber = this.coerceToNumber(elemExpr, 'unary'); + const elementNumber = this.coerceArrayElementToNumber(expr, 'elem', 'unary'); const elementErrorCondition = elementNumber.errorConditionSql; const elementErrorMessage = elementNumber.errorMessageSql ?? buildErrorLiteral('TYPE', 'cannot_cast_to_number'); diff --git a/packages/v2/formula-sql-pg/src/FormulaSqlPgFunctions.ts b/packages/v2/formula-sql-pg/src/FormulaSqlPgFunctions.ts index 9cacc0074..a9f0b4579 100644 --- a/packages/v2/formula-sql-pg/src/FormulaSqlPgFunctions.ts +++ b/packages/v2/formula-sql-pg/src/FormulaSqlPgFunctions.ts @@ -347,14 +347,7 @@ export class FormulaSqlPgFunctions extends FormulaSqlPgExpressionBuilder { reason: string ): SqlExpr { const normalizedArray = this.normalizeArrayExpr(arrayExpr); - const elemExpr = makeExpr( - extractJsonScalarText('elem'), - 'unknown', - false, - arrayExpr.errorConditionSql, - arrayExpr.errorMessageSql - ); - const elementNumber = this.coerceToNumber(elemExpr, reason); + const elementNumber = this.coerceArrayElementToNumber(arrayExpr, 'elem', reason); const elementValueSql = guardValueSql( op(elementNumber.valueSql), elementNumber.errorConditionSql @@ -560,12 +553,11 @@ export class FormulaSqlPgFunctions extends FormulaSqlPgExpressionBuilder { if (!value) return makeExpr('NULL', 'number', false); const numeric = this.coerceToNumber(value, 'even'); const valueSql = this.withValueAlias(numeric.valueSql, (ref) => { - const rounded = `(CASE WHEN ${ref} > 0 THEN CEIL(${ref}) ELSE FLOOR(${ref}) END)`; + const rounded = `FLOOR(${ref})`; const roundedNumeric = `(${rounded})::numeric`; return `(CASE WHEN MOD(${roundedNumeric}, 2::numeric) = 0 THEN ${rounded} - WHEN ${rounded} > 0 THEN ${rounded} + 1 - ELSE ${rounded} - 1 + ELSE (${rounded} + 1) END)`; }); return makeExpr( @@ -582,12 +574,11 @@ export class FormulaSqlPgFunctions extends FormulaSqlPgExpressionBuilder { if (!value) return makeExpr('NULL', 'number', false); const numeric = this.coerceToNumber(value, 'odd'); const valueSql = this.withValueAlias(numeric.valueSql, (ref) => { - const rounded = `(CASE WHEN ${ref} > 0 THEN CEIL(${ref}) ELSE FLOOR(${ref}) END)`; + const rounded = `FLOOR(${ref})`; const roundedNumeric = `(${rounded})::numeric`; return `(CASE WHEN MOD(${roundedNumeric}, 2::numeric) <> 0 THEN ${rounded} - WHEN ${rounded} >= 0 THEN ${rounded} + 1 - ELSE ${rounded} - 1 + ELSE (${rounded} + 1) END)`; }); return makeExpr( @@ -943,7 +934,8 @@ export class FormulaSqlPgFunctions extends FormulaSqlPgExpressionBuilder { const oldText = params[1]; const newText = params[2]; if (!textExpr || !oldText || !newText) return makeExpr('NULL', 'string', false); - const text = this.coerceToString(textExpr); + // Use raw text coercion so numeric values keep runtime precision semantics (e.g. 42.5 vs 42.50). + const text = this.coerceToString(textExpr, false); const search = this.coerceToString(oldText); const replacement = this.coerceToString(newText); const errorCondition = combineErrorConditions([text, search, replacement]); @@ -1037,25 +1029,15 @@ export class FormulaSqlPgFunctions extends FormulaSqlPgExpressionBuilder { private t(params: SqlExpr[]): SqlExpr { const value = params[0]; if (!value) return makeExpr('NULL', 'string', false); - if (value.isArray) { - return makeExpr( - this.stringifyArrayExpr(value), - 'string', - false, - value.errorConditionSql, - value.errorMessageSql - ); - } - if (value.valueType === 'string') { - return makeExpr( - value.valueSql, - 'string', - false, - value.errorConditionSql, - value.errorMessageSql - ); - } - return makeExpr('NULL', 'string', false); + // Keep legacy runtime behavior: T coerces supported scalar/array values to text. + const text = this.coerceToString(value, false); + return makeExpr( + guardValueSql(text.valueSql, text.errorConditionSql), + 'string', + false, + text.errorConditionSql, + text.errorMessageSql + ); } private encodeUrlComponent(params: SqlExpr[]): SqlExpr { @@ -1414,21 +1396,14 @@ export class FormulaSqlPgFunctions extends FormulaSqlPgExpressionBuilder { } private toNow(params: SqlExpr[]): SqlExpr { - const value = params[0]; - if (!value) return makeExpr('NULL', 'number', false); - const unit = params[1]; - const datetime = this.coerceToDatetime(value); - const diffSeconds = `EXTRACT(EPOCH FROM (NOW() - ${datetime.valueSql}))`; - const diffMonths = `EXTRACT(MONTH FROM AGE(NOW(), ${datetime.valueSql})) + EXTRACT(YEAR FROM AGE(NOW(), ${datetime.valueSql})) * 12`; - const diffYears = `EXTRACT(YEAR FROM AGE(NOW(), ${datetime.valueSql}))`; - return this.buildNowDiffWithUnit(datetime, unit, diffSeconds, diffMonths, diffYears); + return this.fromNow(params); } private datetimeDiff(params: SqlExpr[]): SqlExpr { const start = params[0]; const end = params[1]; - const unit = params[2]; - if (!start || !end || !unit) return makeExpr('NULL', 'number', false); + const unit = params[2] ?? makeExpr(sqlStringLiteral('day'), 'string', false); + if (!start || !end) return makeExpr('NULL', 'number', false); const startDt = this.coerceToDatetime(start); const endDt = this.coerceToDatetime(end); const startError = this.shortCircuitOnError( @@ -1446,8 +1421,8 @@ export class FormulaSqlPgFunctions extends FormulaSqlPgExpressionBuilder { ); if (endError) return endError; const diffSeconds = `EXTRACT(EPOCH FROM (${startDt.valueSql} - ${endDt.valueSql}))`; - const diffMonths = `EXTRACT(MONTH FROM AGE(${endDt.valueSql}, ${startDt.valueSql})) + EXTRACT(YEAR FROM AGE(${endDt.valueSql}, ${startDt.valueSql})) * 12`; - const diffYears = `EXTRACT(YEAR FROM AGE(${endDt.valueSql}, ${startDt.valueSql}))`; + const diffMonths = this.buildMonthDiff(startDt.valueSql, endDt.valueSql); + const diffYears = `CAST((${diffMonths}) / 12.0 AS INTEGER)`; const unitLiteral = this.getStringLiteralValue(unit); const normalizedUnit = this.normalizeUnitLiteral(unitLiteral, DATETIME_DIFF_UNIT_ALIASES); if (unitLiteral) { @@ -1516,6 +1491,25 @@ export class FormulaSqlPgFunctions extends FormulaSqlPgExpressionBuilder { ); } + private buildMonthDiff(startSql: string, endSql: string): string { + const startExpr = this.applyFormulaTimeZone(startSql); + const endExpr = this.applyFormulaTimeZone(endSql); + + const startYear = `EXTRACT(YEAR FROM ${startExpr})`; + const endYear = `EXTRACT(YEAR FROM ${endExpr})`; + const startMonth = `EXTRACT(MONTH FROM ${startExpr})`; + const endMonth = `EXTRACT(MONTH FROM ${endExpr})`; + const startDay = `EXTRACT(DAY FROM ${startExpr})`; + const endDay = `EXTRACT(DAY FROM ${endExpr})`; + const startLastDay = `EXTRACT(DAY FROM (DATE_TRUNC('month', ${startExpr}) + INTERVAL '1 month - 1 day'))`; + const endLastDay = `EXTRACT(DAY FROM (DATE_TRUNC('month', ${endExpr}) + INTERVAL '1 month - 1 day'))`; + + const baseMonths = `((${startYear} - ${endYear}) * 12 + (${startMonth} - ${endMonth}))`; + const adjustDown = `(CASE WHEN ${baseMonths} > 0 AND ${startDay} < ${endDay} AND ${startDay} < ${startLastDay} THEN 1 ELSE 0 END)`; + const adjustUp = `(CASE WHEN ${baseMonths} < 0 AND ${startDay} > ${endDay} AND ${endDay} < ${endLastDay} THEN 1 ELSE 0 END)`; + return `(${baseMonths} - ${adjustDown} + ${adjustUp})`; + } + private workday(params: SqlExpr[]): SqlExpr { const start = params[0]; const days = params[1]; diff --git a/packages/v2/formula-sql-pg/src/FromNowToNow.spec.ts b/packages/v2/formula-sql-pg/src/FromNowToNow.spec.ts index 91a9fafe3..b92b0ae18 100644 --- a/packages/v2/formula-sql-pg/src/FromNowToNow.spec.ts +++ b/packages/v2/formula-sql-pg/src/FromNowToNow.spec.ts @@ -44,7 +44,7 @@ describe('FROMNOW / TONOW', () => { expect(dayContext.sql).toContain('/ 86400'); expect(hourContext.sql).toContain('/ 3600'); - expect(secondContext.sql).toContain('TRUNC((EXTRACT(EPOCH FROM (NOW() -'); + expect(secondContext.sql).toContain('EXTRACT(EPOCH FROM (NOW() -'); const dayValue = parseNumericResult(dayContext.result); const hourValue = parseNumericResult(hourContext.result); diff --git a/packages/v2/formula-sql-pg/src/PgSqlHelpers.ts b/packages/v2/formula-sql-pg/src/PgSqlHelpers.ts index 242960b8d..00acc2ef2 100644 --- a/packages/v2/formula-sql-pg/src/PgSqlHelpers.ts +++ b/packages/v2/formula-sql-pg/src/PgSqlHelpers.ts @@ -23,8 +23,8 @@ export const safeJsonb = (expr: string): string => { const trimmedText = `BTRIM(${textSql})`; return `(CASE WHEN ${baseExpr} IS NULL THEN NULL - WHEN pg_typeof(${baseExpr}) = 'jsonb'::regtype THEN (${baseExpr})::jsonb - WHEN pg_typeof(${baseExpr}) = 'json'::regtype THEN (${baseExpr})::jsonb + WHEN pg_typeof(${baseExpr}) = 'jsonb'::regtype THEN to_jsonb(${baseExpr}) + WHEN pg_typeof(${baseExpr}) = 'json'::regtype THEN to_jsonb(${baseExpr}) WHEN NULLIF(${trimmedText}, '') IS NULL THEN NULL ELSE to_jsonb(${baseExpr}) END)`; @@ -42,8 +42,8 @@ export const safeJsonbWithStrategy = ( const jsonValid = typeValidation.isValidForType(textSql, 'jsonb'); return `(CASE WHEN ${baseExpr} IS NULL THEN NULL - WHEN pg_typeof(${baseExpr}) = 'jsonb'::regtype THEN (${baseExpr})::jsonb - WHEN pg_typeof(${baseExpr}) = 'json'::regtype THEN (${baseExpr})::jsonb + WHEN pg_typeof(${baseExpr}) = 'jsonb'::regtype THEN to_jsonb(${baseExpr}) + WHEN pg_typeof(${baseExpr}) = 'json'::regtype THEN to_jsonb(${baseExpr}) WHEN pg_typeof(${baseExpr}) IN (${textTypes}) THEN CASE WHEN NULLIF(${trimmedText}, '') IS NULL THEN NULL diff --git a/packages/v2/formula-sql-pg/src/__snapshots__/ArrayFunctions.spec.ts.snap b/packages/v2/formula-sql-pg/src/__snapshots__/ArrayFunctions.spec.ts.snap index 1c013d050..5d507f2f5 100644 --- a/packages/v2/formula-sql-pg/src/__snapshots__/ArrayFunctions.spec.ts.snap +++ b/packages/v2/formula-sql-pg/src/__snapshots__/ArrayFunctions.spec.ts.snap @@ -201,8 +201,8 @@ exports[`array functions > 'ArrayCompact' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -219,8 +219,8 @@ exports[`array functions > 'ArrayCompact' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -646,8 +646,8 @@ exports[`array functions > 'ArrayCompact' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -664,8 +664,8 @@ exports[`array functions > 'ArrayCompact' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1120,8 +1120,8 @@ exports[`array functions > 'ArrayFlatten' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -1137,8 +1137,8 @@ exports[`array functions > 'ArrayFlatten' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -1545,8 +1545,8 @@ exports[`array functions > 'ArrayFlatten' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1562,8 +1562,8 @@ exports[`array functions > 'ArrayFlatten' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1974,8 +1974,8 @@ exports[`array functions > 'ArrayJoin' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2319,8 +2319,8 @@ exports[`array functions > 'ArrayJoin' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2729,8 +2729,8 @@ exports[`array functions > 'ArrayUnique' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2746,8 +2746,8 @@ exports[`array functions > 'ArrayUnique' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3154,8 +3154,8 @@ exports[`array functions > 'ArrayUnique' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3171,8 +3171,8 @@ exports[`array functions > 'ArrayUnique' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3533,8 +3533,8 @@ exports[`array functions > 'Count' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3768,8 +3768,8 @@ exports[`array functions > 'Count' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4048,8 +4048,8 @@ exports[`array functions > 'CountA' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -4287,8 +4287,8 @@ exports[`array functions > 'CountA' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4569,8 +4569,8 @@ exports[`array functions > 'CountAll' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -4800,8 +4800,8 @@ exports[`array functions > 'CountAll' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL diff --git a/packages/v2/formula-sql-pg/src/__snapshots__/BinaryOperators.spec.ts.snap b/packages/v2/formula-sql-pg/src/__snapshots__/BinaryOperators.spec.ts.snap index e16cfa0b3..6e80121d7 100644 --- a/packages/v2/formula-sql-pg/src/__snapshots__/BinaryOperators.spec.ts.snap +++ b/packages/v2/formula-sql-pg/src/__snapshots__/BinaryOperators.spec.ts.snap @@ -400,8 +400,8 @@ exports[`binary comparison operators > 'Eq' 'conditionalLookup' '=' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -420,8 +420,8 @@ exports[`binary comparison operators > 'Eq' 'conditionalLookup' '=' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -440,8 +440,8 @@ exports[`binary comparison operators > 'Eq' 'conditionalLookup' '=' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -460,8 +460,8 @@ exports[`binary comparison operators > 'Eq' 'conditionalLookup' '=' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -484,8 +484,8 @@ exports[`binary comparison operators > 'Eq' 'conditionalLookup' '=' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -508,8 +508,8 @@ exports[`binary comparison operators > 'Eq' 'conditionalLookup' '=' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -529,8 +529,8 @@ exports[`binary comparison operators > 'Eq' 'conditionalLookup' '=' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -549,8 +549,8 @@ exports[`binary comparison operators > 'Eq' 'conditionalLookup' '=' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -616,13 +616,13 @@ exports[`binary comparison operators > 'Eq' 'createdBy' '=' 'createdBy' 1`] = ` "result": "true", "rightType": "createdBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '') = COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), ''))", } `; @@ -1185,13 +1185,13 @@ exports[`binary comparison operators > 'Eq' 'lastModifiedBy' '=' 'lastModifiedBy "result": "true", "rightType": "lastModifiedBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '') = COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), ''))", } `; @@ -1309,8 +1309,8 @@ exports[`binary comparison operators > 'Eq' 'lookup' '=' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1329,8 +1329,8 @@ exports[`binary comparison operators > 'Eq' 'lookup' '=' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3217,8 +3217,8 @@ exports[`binary comparison operators > 'Gt' 'conditionalLookup' '>' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3237,8 +3237,8 @@ exports[`binary comparison operators > 'Gt' 'conditionalLookup' '>' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3257,8 +3257,8 @@ exports[`binary comparison operators > 'Gt' 'conditionalLookup' '>' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3277,8 +3277,8 @@ exports[`binary comparison operators > 'Gt' 'conditionalLookup' '>' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3301,8 +3301,8 @@ exports[`binary comparison operators > 'Gt' 'conditionalLookup' '>' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3325,8 +3325,8 @@ exports[`binary comparison operators > 'Gt' 'conditionalLookup' '>' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3346,8 +3346,8 @@ exports[`binary comparison operators > 'Gt' 'conditionalLookup' '>' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3366,8 +3366,8 @@ exports[`binary comparison operators > 'Gt' 'conditionalLookup' '>' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3433,13 +3433,13 @@ exports[`binary comparison operators > 'Gt' 'createdBy' '>' 'createdBy' 1`] = ` "result": "false", "rightType": "createdBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '') > COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), ''))", } `; @@ -4002,13 +4002,13 @@ exports[`binary comparison operators > 'Gt' 'lastModifiedBy' '>' 'lastModifiedBy "result": "false", "rightType": "lastModifiedBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '') > COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), ''))", } `; @@ -4126,8 +4126,8 @@ exports[`binary comparison operators > 'Gt' 'lookup' '>' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4146,8 +4146,8 @@ exports[`binary comparison operators > 'Gt' 'lookup' '>' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6034,8 +6034,8 @@ exports[`binary comparison operators > 'Gte' 'conditionalLookup' '>=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6054,8 +6054,8 @@ exports[`binary comparison operators > 'Gte' 'conditionalLookup' '>=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6074,8 +6074,8 @@ exports[`binary comparison operators > 'Gte' 'conditionalLookup' '>=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6094,8 +6094,8 @@ exports[`binary comparison operators > 'Gte' 'conditionalLookup' '>=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6118,8 +6118,8 @@ exports[`binary comparison operators > 'Gte' 'conditionalLookup' '>=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6142,8 +6142,8 @@ exports[`binary comparison operators > 'Gte' 'conditionalLookup' '>=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6163,8 +6163,8 @@ exports[`binary comparison operators > 'Gte' 'conditionalLookup' '>=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6183,8 +6183,8 @@ exports[`binary comparison operators > 'Gte' 'conditionalLookup' '>=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6250,13 +6250,13 @@ exports[`binary comparison operators > 'Gte' 'createdBy' '>=' 'createdBy' 1`] = "result": "true", "rightType": "createdBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '') >= COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), ''))", } `; @@ -6819,13 +6819,13 @@ exports[`binary comparison operators > 'Gte' 'lastModifiedBy' '>=' 'lastModified "result": "true", "rightType": "lastModifiedBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '') >= COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), ''))", } `; @@ -6943,8 +6943,8 @@ exports[`binary comparison operators > 'Gte' 'lookup' '>=' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6963,8 +6963,8 @@ exports[`binary comparison operators > 'Gte' 'lookup' '>=' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8851,8 +8851,8 @@ exports[`binary comparison operators > 'Lt' 'conditionalLookup' '<' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8871,8 +8871,8 @@ exports[`binary comparison operators > 'Lt' 'conditionalLookup' '<' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8891,8 +8891,8 @@ exports[`binary comparison operators > 'Lt' 'conditionalLookup' '<' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8911,8 +8911,8 @@ exports[`binary comparison operators > 'Lt' 'conditionalLookup' '<' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8935,8 +8935,8 @@ exports[`binary comparison operators > 'Lt' 'conditionalLookup' '<' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8959,8 +8959,8 @@ exports[`binary comparison operators > 'Lt' 'conditionalLookup' '<' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8980,8 +8980,8 @@ exports[`binary comparison operators > 'Lt' 'conditionalLookup' '<' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9000,8 +9000,8 @@ exports[`binary comparison operators > 'Lt' 'conditionalLookup' '<' 'conditional ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9067,13 +9067,13 @@ exports[`binary comparison operators > 'Lt' 'createdBy' '<' 'createdBy' 1`] = ` "result": "false", "rightType": "createdBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '') < COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), ''))", } `; @@ -9636,13 +9636,13 @@ exports[`binary comparison operators > 'Lt' 'lastModifiedBy' '<' 'lastModifiedBy "result": "false", "rightType": "lastModifiedBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '') < COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), ''))", } `; @@ -9760,8 +9760,8 @@ exports[`binary comparison operators > 'Lt' 'lookup' '<' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9780,8 +9780,8 @@ exports[`binary comparison operators > 'Lt' 'lookup' '<' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11668,8 +11668,8 @@ exports[`binary comparison operators > 'Lte' 'conditionalLookup' '<=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11688,8 +11688,8 @@ exports[`binary comparison operators > 'Lte' 'conditionalLookup' '<=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11708,8 +11708,8 @@ exports[`binary comparison operators > 'Lte' 'conditionalLookup' '<=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11728,8 +11728,8 @@ exports[`binary comparison operators > 'Lte' 'conditionalLookup' '<=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11752,8 +11752,8 @@ exports[`binary comparison operators > 'Lte' 'conditionalLookup' '<=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11776,8 +11776,8 @@ exports[`binary comparison operators > 'Lte' 'conditionalLookup' '<=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11797,8 +11797,8 @@ exports[`binary comparison operators > 'Lte' 'conditionalLookup' '<=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11817,8 +11817,8 @@ exports[`binary comparison operators > 'Lte' 'conditionalLookup' '<=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11884,13 +11884,13 @@ exports[`binary comparison operators > 'Lte' 'createdBy' '<=' 'createdBy' 1`] = "result": "true", "rightType": "createdBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '') <= COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), ''))", } `; @@ -12453,13 +12453,13 @@ exports[`binary comparison operators > 'Lte' 'lastModifiedBy' '<=' 'lastModified "result": "true", "rightType": "lastModifiedBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '') <= COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), ''))", } `; @@ -12577,8 +12577,8 @@ exports[`binary comparison operators > 'Lte' 'lookup' '<=' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12597,8 +12597,8 @@ exports[`binary comparison operators > 'Lte' 'lookup' '<=' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14485,8 +14485,8 @@ exports[`binary comparison operators > 'Neq' 'conditionalLookup' '!=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -14505,8 +14505,8 @@ exports[`binary comparison operators > 'Neq' 'conditionalLookup' '!=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -14525,8 +14525,8 @@ exports[`binary comparison operators > 'Neq' 'conditionalLookup' '!=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -14545,8 +14545,8 @@ exports[`binary comparison operators > 'Neq' 'conditionalLookup' '!=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -14569,8 +14569,8 @@ exports[`binary comparison operators > 'Neq' 'conditionalLookup' '!=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -14593,8 +14593,8 @@ exports[`binary comparison operators > 'Neq' 'conditionalLookup' '!=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -14614,8 +14614,8 @@ exports[`binary comparison operators > 'Neq' 'conditionalLookup' '!=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -14634,8 +14634,8 @@ exports[`binary comparison operators > 'Neq' 'conditionalLookup' '!=' 'condition ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -14701,13 +14701,13 @@ exports[`binary comparison operators > 'Neq' 'createdBy' '!=' 'createdBy' 1`] = "result": "false", "rightType": "createdBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '') <> COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), ''))", } `; @@ -15270,13 +15270,13 @@ exports[`binary comparison operators > 'Neq' 'lastModifiedBy' '!=' 'lastModified "result": "false", "rightType": "lastModifiedBy", "sql": "(COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '') <> COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), ''))", } `; @@ -15394,8 +15394,8 @@ exports[`binary comparison operators > 'Neq' 'lookup' '!=' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -15414,8 +15414,8 @@ exports[`binary comparison operators > 'Neq' 'lookup' '!=' 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL diff --git a/packages/v2/formula-sql-pg/src/__snapshots__/DateFunctions.spec.ts.snap b/packages/v2/formula-sql-pg/src/__snapshots__/DateFunctions.spec.ts.snap index 6259993e9..a060c9c74 100644 --- a/packages/v2/formula-sql-pg/src/__snapshots__/DateFunctions.spec.ts.snap +++ b/packages/v2/formula-sql-pg/src/__snapshots__/DateFunctions.spec.ts.snap @@ -126,8 +126,8 @@ exports[`date functions batch 1 > 'Day' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -381,8 +381,8 @@ exports[`date functions batch 1 > 'Day' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -684,8 +684,8 @@ exports[`date functions batch 1 > 'Hour' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -939,8 +939,8 @@ exports[`date functions batch 1 > 'Hour' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1242,8 +1242,8 @@ exports[`date functions batch 1 > 'Minute' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -1497,8 +1497,8 @@ exports[`date functions batch 1 > 'Minute' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1800,8 +1800,8 @@ exports[`date functions batch 1 > 'Month' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2055,8 +2055,8 @@ exports[`date functions batch 1 > 'Month' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2358,8 +2358,8 @@ exports[`date functions batch 1 > 'WeekNum' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2613,8 +2613,8 @@ exports[`date functions batch 1 > 'WeekNum' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2916,8 +2916,8 @@ exports[`date functions batch 1 > 'Weekday' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3171,8 +3171,8 @@ exports[`date functions batch 1 > 'Weekday' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3474,8 +3474,8 @@ exports[`date functions batch 1 > 'Year' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3729,8 +3729,8 @@ exports[`date functions batch 1 > 'Year' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3940,7 +3940,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'autoNumber' 1`] = ` }, }, "result": "-1", - "sql": "TRUNC((EXTRACT(EPOCH FROM (to_timestamp(("t"."AutoNumber")::double precision) - (to_timestamp(("t"."AutoNumber")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (to_timestamp(("t"."AutoNumber")::double precision) - (to_timestamp(("t"."AutoNumber")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (to_timestamp(("t"."AutoNumber")::double precision) - (to_timestamp(("t"."AutoNumber")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4007,7 +4007,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'conditionalLookup' 1`] = }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (to_timestamp(((SELECT CASE + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (to_timestamp(((SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE (lkp.elem #>> '{}')::numeric END @@ -4018,8 +4018,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -4038,8 +4038,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -4047,7 +4047,47 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'conditionalLookup' 1`] = ELSE to_jsonb((("t"."ConditionalLookupType"))) END ELSE to_jsonb((("t"."ConditionalLookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (to_timestamp(((SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE (lkp.elem #>> '{}')::numeric + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."ConditionalLookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."ConditionalLookupType")))::text, 'jsonb') THEN (((("t"."ConditionalLookupType")))::text)::jsonb + ELSE to_jsonb((("t"."ConditionalLookupType"))) + END + ELSE to_jsonb((("t"."ConditionalLookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision) - (to_timestamp(((SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE (lkp.elem #>> '{}')::numeric + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."ConditionalLookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."ConditionalLookupType")))::text, 'jsonb') THEN (((("t"."ConditionalLookupType")))::text)::jsonb + ELSE to_jsonb((("t"."ConditionalLookupType"))) + END + ELSE to_jsonb((("t"."ConditionalLookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4069,7 +4109,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'conditionalRollup' 1`] = }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (to_timestamp(("t"."ConditionalRollupType")::double precision) - (to_timestamp(("t"."ConditionalRollupType")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (to_timestamp(("t"."ConditionalRollupType")::double precision) - (to_timestamp(("t"."ConditionalRollupType")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (to_timestamp(("t"."ConditionalRollupType")::double precision) - (to_timestamp(("t"."ConditionalRollupType")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4111,7 +4151,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'createdTime' 1`] = ` }, }, "result": "-0", - "sql": "TRUNC((EXTRACT(EPOCH FROM (("t"."CreatedTime")::timestamptz - (("t"."CreatedTime")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (("t"."CreatedTime")::timestamptz - (("t"."CreatedTime")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (("t"."CreatedTime")::timestamptz - (("t"."CreatedTime")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4134,7 +4174,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'date' 1`] = ` }, }, "result": "-1", - "sql": "TRUNC((EXTRACT(EPOCH FROM (("t"."Date")::timestamptz - (("t"."Date")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (("t"."Date")::timestamptz - (("t"."Date")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (("t"."Date")::timestamptz - (("t"."Date")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4156,7 +4196,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'formula' 1`] = ` }, }, "result": "-1", - "sql": "TRUNC((EXTRACT(EPOCH FROM (to_timestamp((10)::double precision) - (to_timestamp((10)::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (to_timestamp((10)::double precision) - (to_timestamp((10)::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (to_timestamp((10)::double precision) - (to_timestamp((10)::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4198,7 +4238,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lastModifiedTime' 1`] = ` }, }, "result": "-0", - "sql": "TRUNC((EXTRACT(EPOCH FROM (("t"."LastModifiedTime")::timestamptz - (("t"."LastModifiedTime")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (("t"."LastModifiedTime")::timestamptz - (("t"."LastModifiedTime")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (("t"."LastModifiedTime")::timestamptz - (("t"."LastModifiedTime")::timestamptz + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4236,7 +4276,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'longText' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v)) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE '#ERROR:TYPE:invalid_date_add' END ELSE '#ERROR:TYPE:invalid_datetime_diff' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v)) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v)) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE '#ERROR:TYPE:invalid_date_add' END ELSE '#ERROR:TYPE:invalid_datetime_diff' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v)) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -4246,7 +4286,17 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'longText' 1`] = ` WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT "t"."LongText" AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz))) / 86400) END))::text END", + END) FROM (SELECT "t"."LongText" AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT "t"."LongText" AS val) AS v) END) - ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT "t"."LongText" AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz))) / 86400) END) END))::text END", } `; @@ -4283,8 +4333,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4303,8 +4353,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4323,8 +4373,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4343,8 +4393,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4363,8 +4413,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4383,8 +4433,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4403,8 +4453,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4423,8 +4473,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4443,8 +4493,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4452,7 +4502,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE to_jsonb((("t"."LookupType"))) END ELSE to_jsonb((("t"."LookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v)) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v)) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE lkp.elem #>> '{}' END @@ -4463,8 +4513,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4488,8 +4538,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4508,8 +4558,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4528,8 +4578,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4553,8 +4603,8 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4562,7 +4612,117 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'lookup' 1`] = ` ELSE to_jsonb((("t"."LookupType"))) END ELSE to_jsonb((("t"."LookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz))) / 86400) END))::text END", + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END) - ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz))) / 86400) END) END))::text END", } `; @@ -4603,7 +4763,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'number' 1`] = ` }, }, "result": "-1", - "sql": "TRUNC((EXTRACT(EPOCH FROM (to_timestamp(("t"."Number")::double precision) - (to_timestamp(("t"."Number")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (to_timestamp(("t"."Number")::double precision) - (to_timestamp(("t"."Number")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (to_timestamp(("t"."Number")::double precision) - (to_timestamp(("t"."Number")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4622,7 +4782,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'rating' 1`] = ` }, }, "result": "-1", - "sql": "TRUNC((EXTRACT(EPOCH FROM (to_timestamp(("t"."Rating")::double precision) - (to_timestamp(("t"."Rating")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (to_timestamp(("t"."Rating")::double precision) - (to_timestamp(("t"."Rating")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (to_timestamp(("t"."Rating")::double precision) - (to_timestamp(("t"."Rating")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4644,7 +4804,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'rollup' 1`] = ` }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (to_timestamp(("t"."RollupType")::double precision) - (to_timestamp(("t"."RollupType")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (to_timestamp(("t"."RollupType")::double precision) - (to_timestamp(("t"."RollupType")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (to_timestamp(("t"."RollupType")::double precision) - (to_timestamp(("t"."RollupType")::double precision) + ((1)::double precision) * INTERVAL '1 day')::timestamptz))) / 86400) END)", } `; @@ -4663,7 +4823,7 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'singleLineText' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v)) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE '#ERROR:TYPE:invalid_date_add' END ELSE '#ERROR:TYPE:invalid_datetime_diff' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v)) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v)) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE '#ERROR:TYPE:invalid_date_add' END ELSE '#ERROR:TYPE:invalid_datetime_diff' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v)) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -4673,7 +4833,17 @@ exports[`date functions batch 2 > 'DatetimeDiff' with 'singleLineText' 1`] = ` WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz))) / 86400) END))::text END", + END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END) - ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 day' END))::timestamptz))) / 86400) END) END))::text END", } `; @@ -5464,8 +5634,8 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'longText' 1`] = }, }, "result": "#ERROR:ARG:invalid_datetime_diff_unit", - "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'second', 'seconds', 'minute', 'minutes', 'hour', 'hours', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'second', 'seconds', 'minute', 'minutes', 'hour', 'hours', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years')) THEN '#ERROR:ARG:invalid_datetime_diff_unit' ELSE '#ERROR:ARG:invalid_datetime_diff_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'second', 'seconds', 'minute', 'minutes', 'hour', 'hours', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years'))) THEN NULL ELSE (CASE - WHEN LOWER("t"."LongText") IN ('millisecond', 'milliseconds') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'ms', 'second', 'seconds', 's', 'sec', 'secs', 'minute', 'minutes', 'min', 'mins', 'hour', 'hours', 'h', 'hr', 'hrs', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'ms', 'second', 'seconds', 's', 'sec', 'secs', 'minute', 'minutes', 'min', 'mins', 'hour', 'hours', 'h', 'hr', 'hrs', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years')) THEN '#ERROR:ARG:invalid_datetime_diff_unit' ELSE '#ERROR:ARG:invalid_datetime_diff_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'ms', 'second', 'seconds', 's', 'sec', 'secs', 'minute', 'minutes', 'min', 'mins', 'hour', 'hours', 'h', 'hr', 'hrs', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years'))) THEN NULL ELSE (CASE + WHEN LOWER("t"."LongText") IN ('millisecond', 'milliseconds', 'ms') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5476,7 +5646,7 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'longText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) * 1000) - WHEN LOWER("t"."LongText") IN ('second', 'seconds') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."LongText") IN ('second', 'seconds', 's', 'sec', 'secs') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5487,7 +5657,7 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'longText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END))))) - WHEN LOWER("t"."LongText") IN ('minute', 'minutes') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."LongText") IN ('minute', 'minutes', 'min', 'mins') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5498,7 +5668,7 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'longText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / 60) - WHEN LOWER("t"."LongText") IN ('hour', 'hours') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."LongText") IN ('hour', 'hours', 'h', 'hr', 'hrs') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5509,7 +5679,7 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'longText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / 3600) - WHEN LOWER("t"."LongText") IN ('week', 'weeks') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."LongText") IN ('week', 'weeks') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5520,60 +5690,310 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'longText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / (86400 * 7)) - WHEN LOWER("t"."LongText") IN ('month', 'months') THEN TRUNC(EXTRACT(MONTH FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."LongText") IN ('month', 'months') THEN (((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END))) + EXTRACT(YEAR FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END))) * 12) - WHEN LOWER("t"."LongText") IN ('quarter', 'quarters') THEN TRUNC((EXTRACT(MONTH FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) - (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END))) + EXTRACT(YEAR FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END))) * 12) / 3.0) - WHEN LOWER("t"."LongText") IN ('year', 'years') THEN TRUNC(EXTRACT(YEAR FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) > 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)))) - WHEN LOWER("t"."LongText") IN ('day', 'days') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END) + (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) < 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') > EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END)) + WHEN LOWER("t"."LongText") IN ('quarter', 'quarters') THEN (((((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) - (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) > 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END) + (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) < 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') > EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END))) / 3.0) + WHEN LOWER("t"."LongText") IN ('year', 'years') THEN CAST(((((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) - (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) > 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END) + (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) < 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') > EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END))) / 12.0 AS INTEGER) + WHEN LOWER("t"."LongText") IN ('day', 'days') THEN (CASE WHEN ABS((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5583,7 +6003,17 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'longText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / 86400) + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / 86400) END) ELSE NULL::double precision END) END))::text END", } @@ -5712,8 +6142,8 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'singleLineText' }, }, "result": "#ERROR:ARG:invalid_datetime_diff_unit", - "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'second', 'seconds', 'minute', 'minutes', 'hour', 'hours', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'second', 'seconds', 'minute', 'minutes', 'hour', 'hours', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years')) THEN '#ERROR:ARG:invalid_datetime_diff_unit' ELSE '#ERROR:ARG:invalid_datetime_diff_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'second', 'seconds', 'minute', 'minutes', 'hour', 'hours', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years'))) THEN NULL ELSE (CASE - WHEN LOWER("t"."SingleLineText") IN ('millisecond', 'milliseconds') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'ms', 'second', 'seconds', 's', 'sec', 'secs', 'minute', 'minutes', 'min', 'mins', 'hour', 'hours', 'h', 'hr', 'hrs', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'ms', 'second', 'seconds', 's', 'sec', 'secs', 'minute', 'minutes', 'min', 'mins', 'hour', 'hours', 'h', 'hr', 'hrs', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years')) THEN '#ERROR:ARG:invalid_datetime_diff_unit' ELSE '#ERROR:ARG:invalid_datetime_diff_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'ms', 'second', 'seconds', 's', 'sec', 'secs', 'minute', 'minutes', 'min', 'mins', 'hour', 'hours', 'h', 'hr', 'hrs', 'day', 'days', 'week', 'weeks', 'month', 'months', 'quarter', 'quarters', 'year', 'years'))) THEN NULL ELSE (CASE + WHEN LOWER("t"."SingleLineText") IN ('millisecond', 'milliseconds', 'ms') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5724,7 +6154,7 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'singleLineText' WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) * 1000) - WHEN LOWER("t"."SingleLineText") IN ('second', 'seconds') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."SingleLineText") IN ('second', 'seconds', 's', 'sec', 'secs') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5735,7 +6165,7 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'singleLineText' WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END))))) - WHEN LOWER("t"."SingleLineText") IN ('minute', 'minutes') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."SingleLineText") IN ('minute', 'minutes', 'min', 'mins') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5746,7 +6176,7 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'singleLineText' WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / 60) - WHEN LOWER("t"."SingleLineText") IN ('hour', 'hours') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."SingleLineText") IN ('hour', 'hours', 'h', 'hr', 'hrs') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5757,7 +6187,7 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'singleLineText' WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / 3600) - WHEN LOWER("t"."SingleLineText") IN ('week', 'weeks') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."SingleLineText") IN ('week', 'weeks') THEN ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5768,60 +6198,310 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'singleLineText' WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / (86400 * 7)) - WHEN LOWER("t"."SingleLineText") IN ('month', 'months') THEN TRUNC(EXTRACT(MONTH FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN LOWER("t"."SingleLineText") IN ('month', 'months') THEN (((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END))) + EXTRACT(YEAR FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END))) * 12) - WHEN LOWER("t"."SingleLineText") IN ('quarter', 'quarters') THEN TRUNC((EXTRACT(MONTH FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) - (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END))) + EXTRACT(YEAR FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END))) * 12) / 3.0) - WHEN LOWER("t"."SingleLineText") IN ('year', 'years') THEN TRUNC(EXTRACT(YEAR FROM AGE((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) > 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END), (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)))) - WHEN LOWER("t"."SingleLineText") IN ('day', 'days') THEN TRUNC((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END) + (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) < 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') > EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END)) + WHEN LOWER("t"."SingleLineText") IN ('quarter', 'quarters') THEN (((((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) - (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) > 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END) + (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) < 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') > EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END))) / 3.0) + WHEN LOWER("t"."SingleLineText") IN ('year', 'years') THEN CAST(((((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) - (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) > 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END) + (CASE WHEN ((EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(YEAR FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC')) * 12 + (EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') - EXTRACT(MONTH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC'))) < 0 AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') > EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') AND EXTRACT(DAY FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') < EXTRACT(DAY FROM (DATE_TRUNC('month', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + INTERVAL '1 month - 1 day')) THEN 1 ELSE 0 END))) / 12.0 AS INTEGER) + WHEN LOWER("t"."SingleLineText") IN ('day', 'days') THEN (CASE WHEN ABS((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -5831,7 +6511,17 @@ exports[`date functions batch 2 > 'DatetimeDiffUnitField' with 'singleLineText' WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / 86400) + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)))) / 86400) END) ELSE NULL::double precision END) END))::text END", } @@ -5890,7 +6580,7 @@ exports[`date functions batch 2 > 'FromNow' with 'attachment' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -5908,8 +6598,8 @@ exports[`date functions batch 2 > 'FromNow' with 'autoNumber' 1`] = ` "rawValue": "1", }, }, - "result": "00000", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."AutoNumber")::double precision)))) / 86400)", + "result": "00000.000000000000", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."AutoNumber")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."AutoNumber")::double precision)))) / 86400) END)", } `; @@ -5928,7 +6618,7 @@ exports[`date functions batch 2 > 'FromNow' with 'button' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -5947,7 +6637,7 @@ exports[`date functions batch 2 > 'FromNow' with 'checkbox' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_boolean_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_boolean_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_boolean_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -5976,7 +6666,7 @@ exports[`date functions batch 2 > 'FromNow' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(((SELECT CASE + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(((SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE (lkp.elem #>> '{}')::numeric END @@ -5987,8 +6677,8 @@ exports[`date functions batch 2 > 'FromNow' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -5996,7 +6686,27 @@ exports[`date functions batch 2 > 'FromNow' with 'conditionalLookup' 1`] = ` ELSE to_jsonb((("t"."ConditionalLookupType"))) END ELSE to_jsonb((("t"."ConditionalLookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision)))) / 86400)", + END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(((SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE (lkp.elem #>> '{}')::numeric + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."ConditionalLookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."ConditionalLookupType")))::text, 'jsonb') THEN (((("t"."ConditionalLookupType")))::text)::jsonb + ELSE to_jsonb((("t"."ConditionalLookupType"))) + END + ELSE to_jsonb((("t"."ConditionalLookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision)))) / 86400) END)", } `; @@ -6018,7 +6728,7 @@ exports[`date functions batch 2 > 'FromNow' with 'conditionalRollup' 1`] = ` }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."ConditionalRollupType")::double precision)))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."ConditionalRollupType")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."ConditionalRollupType")::double precision)))) / 86400) END)", } `; @@ -6037,7 +6747,7 @@ exports[`date functions batch 2 > 'FromNow' with 'createdBy' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -6060,7 +6770,7 @@ exports[`date functions batch 2 > 'FromNow' with 'createdTime' 1`] = ` }, }, "result": "0", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - ("t"."CreatedTime")::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - ("t"."CreatedTime")::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - ("t"."CreatedTime")::timestamptz))) / 86400) END)", } `; @@ -6083,7 +6793,7 @@ exports[`date functions batch 2 > 'FromNow' with 'date' 1`] = ` }, }, "result": "-00", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - ("t"."Date")::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - ("t"."Date")::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - ("t"."Date")::timestamptz))) / 86400) END)", } `; @@ -6104,8 +6814,8 @@ exports[`date functions batch 2 > 'FromNow' with 'formula' 1`] = ` "rawValue": null, }, }, - "result": "00000", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp((10)::double precision)))) / 86400)", + "result": "00000.000000000000", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp((10)::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp((10)::double precision)))) / 86400) END)", } `; @@ -6124,7 +6834,7 @@ exports[`date functions batch 2 > 'FromNow' with 'lastModifiedBy' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -6147,7 +6857,7 @@ exports[`date functions batch 2 > 'FromNow' with 'lastModifiedTime' 1`] = ` }, }, "result": "0", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - ("t"."LastModifiedTime")::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - ("t"."LastModifiedTime")::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - ("t"."LastModifiedTime")::timestamptz))) / 86400) END)", } `; @@ -6166,7 +6876,7 @@ exports[`date functions batch 2 > 'FromNow' with 'link' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -6185,12 +6895,17 @@ exports[`date functions batch 2 > 'FromNow' with 'longText' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + "sql": "CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT "t"."LongText" AS val) AS v) END)))) / 86400) END))::text END", + END) FROM (SELECT "t"."LongText" AS val) AS v) END))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT "t"."LongText" AS val) AS v) END)))) / 86400) END) END))::text END", } `; @@ -6227,8 +6942,8 @@ exports[`date functions batch 2 > 'FromNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6247,8 +6962,8 @@ exports[`date functions batch 2 > 'FromNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6267,8 +6982,8 @@ exports[`date functions batch 2 > 'FromNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6276,7 +6991,7 @@ exports[`date functions batch 2 > 'FromNow' with 'lookup' 1`] = ` ELSE to_jsonb((("t"."LookupType"))) END ELSE to_jsonb((("t"."LookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE lkp.elem #>> '{}' END @@ -6287,8 +7002,8 @@ exports[`date functions batch 2 > 'FromNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6312,8 +7027,8 @@ exports[`date functions batch 2 > 'FromNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6321,7 +7036,52 @@ exports[`date functions batch 2 > 'FromNow' with 'lookup' 1`] = ` ELSE to_jsonb((("t"."LookupType"))) END ELSE to_jsonb((("t"."LookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END)))) / 86400) END))::text END", + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END)))) / 86400) END) END))::text END", } `; @@ -6340,7 +7100,7 @@ exports[`date functions batch 2 > 'FromNow' with 'multipleSelect' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -6361,8 +7121,8 @@ exports[`date functions batch 2 > 'FromNow' with 'number' 1`] = ` "rawValue": "10", }, }, - "result": "00000", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Number")::double precision)))) / 86400)", + "result": "00000.000000000000", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Number")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Number")::double precision)))) / 86400) END)", } `; @@ -6380,8 +7140,8 @@ exports[`date functions batch 2 > 'FromNow' with 'rating' 1`] = ` "rawValue": "4", }, }, - "result": "00000", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Rating")::double precision)))) / 86400)", + "result": "00000.000000000000", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Rating")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Rating")::double precision)))) / 86400) END)", } `; @@ -6403,7 +7163,7 @@ exports[`date functions batch 2 > 'FromNow' with 'rollup' 1`] = ` }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."RollupType")::double precision)))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."RollupType")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."RollupType")::double precision)))) / 86400) END)", } `; @@ -6422,12 +7182,17 @@ exports[`date functions batch 2 > 'FromNow' with 'singleLineText' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + "sql": "CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END)))) / 86400) END))::text END", + END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END)))) / 86400) END) END))::text END", } `; @@ -6446,7 +7211,7 @@ exports[`date functions batch 2 > 'FromNow' with 'singleSelect' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -6465,7 +7230,7 @@ exports[`date functions batch 2 > 'FromNow' with 'user' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -6595,8 +7360,8 @@ exports[`date functions batch 2 > 'Second' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6850,8 +7615,8 @@ exports[`date functions batch 2 > 'Second' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7042,7 +7807,7 @@ exports[`date functions batch 2 > 'ToNow' with 'attachment' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7060,8 +7825,8 @@ exports[`date functions batch 2 > 'ToNow' with 'autoNumber' 1`] = ` "rawValue": "1", }, }, - "result": "00000", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."AutoNumber")::double precision)))) / 86400)", + "result": "00000.000000000000", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."AutoNumber")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."AutoNumber")::double precision)))) / 86400) END)", } `; @@ -7080,7 +7845,7 @@ exports[`date functions batch 2 > 'ToNow' with 'button' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7099,7 +7864,7 @@ exports[`date functions batch 2 > 'ToNow' with 'checkbox' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_boolean_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_boolean_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_boolean_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7128,7 +7893,7 @@ exports[`date functions batch 2 > 'ToNow' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(((SELECT CASE + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(((SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE (lkp.elem #>> '{}')::numeric END @@ -7139,8 +7904,8 @@ exports[`date functions batch 2 > 'ToNow' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -7148,7 +7913,27 @@ exports[`date functions batch 2 > 'ToNow' with 'conditionalLookup' 1`] = ` ELSE to_jsonb((("t"."ConditionalLookupType"))) END ELSE to_jsonb((("t"."ConditionalLookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision)))) / 86400)", + END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(((SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE (lkp.elem #>> '{}')::numeric + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."ConditionalLookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."ConditionalLookupType")))::text, 'jsonb') THEN (((("t"."ConditionalLookupType")))::text)::jsonb + ELSE to_jsonb((("t"."ConditionalLookupType"))) + END + ELSE to_jsonb((("t"."ConditionalLookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp))::double precision)))) / 86400) END)", } `; @@ -7170,7 +7955,7 @@ exports[`date functions batch 2 > 'ToNow' with 'conditionalRollup' 1`] = ` }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."ConditionalRollupType")::double precision)))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."ConditionalRollupType")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."ConditionalRollupType")::double precision)))) / 86400) END)", } `; @@ -7189,7 +7974,7 @@ exports[`date functions batch 2 > 'ToNow' with 'createdBy' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7212,7 +7997,7 @@ exports[`date functions batch 2 > 'ToNow' with 'createdTime' 1`] = ` }, }, "result": "0", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - ("t"."CreatedTime")::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - ("t"."CreatedTime")::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - ("t"."CreatedTime")::timestamptz))) / 86400) END)", } `; @@ -7235,7 +8020,7 @@ exports[`date functions batch 2 > 'ToNow' with 'date' 1`] = ` }, }, "result": "-00", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - ("t"."Date")::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - ("t"."Date")::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - ("t"."Date")::timestamptz))) / 86400) END)", } `; @@ -7256,8 +8041,8 @@ exports[`date functions batch 2 > 'ToNow' with 'formula' 1`] = ` "rawValue": null, }, }, - "result": "00000", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp((10)::double precision)))) / 86400)", + "result": "00000.000000000000", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp((10)::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp((10)::double precision)))) / 86400) END)", } `; @@ -7276,7 +8061,7 @@ exports[`date functions batch 2 > 'ToNow' with 'lastModifiedBy' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7299,7 +8084,7 @@ exports[`date functions batch 2 > 'ToNow' with 'lastModifiedTime' 1`] = ` }, }, "result": "0", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - ("t"."LastModifiedTime")::timestamptz))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - ("t"."LastModifiedTime")::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - ("t"."LastModifiedTime")::timestamptz))) / 86400) END)", } `; @@ -7318,7 +8103,7 @@ exports[`date functions batch 2 > 'ToNow' with 'link' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7337,12 +8122,17 @@ exports[`date functions batch 2 > 'ToNow' with 'longText' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + "sql": "CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT "t"."LongText" AS val) AS v) END)))) / 86400) END))::text END", + END) FROM (SELECT "t"."LongText" AS val) AS v) END))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT "t"."LongText" AS val) AS v) END)))) / 86400) END) END))::text END", } `; @@ -7379,8 +8169,8 @@ exports[`date functions batch 2 > 'ToNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7399,8 +8189,8 @@ exports[`date functions batch 2 > 'ToNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7419,8 +8209,8 @@ exports[`date functions batch 2 > 'ToNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7428,7 +8218,7 @@ exports[`date functions batch 2 > 'ToNow' with 'lookup' 1`] = ` ELSE to_jsonb((("t"."LookupType"))) END ELSE to_jsonb((("t"."LookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE lkp.elem #>> '{}' END @@ -7439,8 +8229,8 @@ exports[`date functions batch 2 > 'ToNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7464,8 +8254,8 @@ exports[`date functions batch 2 > 'ToNow' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7473,7 +8263,52 @@ exports[`date functions batch 2 > 'ToNow' with 'lookup' 1`] = ` ELSE to_jsonb((("t"."LookupType"))) END ELSE to_jsonb((("t"."LookupType"))) - END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END)))) / 86400) END))::text END", + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT (SELECT CASE + WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL + ELSE lkp.elem #>> '{}' + END + FROM (SELECT ((SELECT CASE + WHEN _lkp.v IS NULL THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb + WHEN jsonb_typeof(_lkp.v) = 'array' THEN _lkp.v + ELSE jsonb_build_array(_lkp.v) + END FROM (SELECT (CASE + WHEN (("t"."LookupType")) IS NULL THEN NULL + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN + CASE + WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL + WHEN (LEFT(BTRIM(((("t"."LookupType")))::text), 1) IN ('[', '{')) AND __teable_input_is_valid(((("t"."LookupType")))::text, 'jsonb') THEN (((("t"."LookupType")))::text)::jsonb + ELSE to_jsonb((("t"."LookupType"))) + END + ELSE to_jsonb((("t"."LookupType"))) + END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) END)))) / 86400) END) END))::text END", } `; @@ -7492,7 +8327,7 @@ exports[`date functions batch 2 > 'ToNow' with 'multipleSelect' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7513,8 +8348,8 @@ exports[`date functions batch 2 > 'ToNow' with 'number' 1`] = ` "rawValue": "10", }, }, - "result": "00000", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Number")::double precision)))) / 86400)", + "result": "00000.000000000000", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Number")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Number")::double precision)))) / 86400) END)", } `; @@ -7532,8 +8367,8 @@ exports[`date functions batch 2 > 'ToNow' with 'rating' 1`] = ` "rawValue": "4", }, }, - "result": "00000", - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Rating")::double precision)))) / 86400)", + "result": "00000.000000000000", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Rating")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."Rating")::double precision)))) / 86400) END)", } `; @@ -7555,7 +8390,7 @@ exports[`date functions batch 2 > 'ToNow' with 'rollup' 1`] = ` }, }, "result": null, - "sql": "TRUNC((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."RollupType")::double precision)))) / 86400)", + "sql": "(CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."RollupType")::double precision))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - to_timestamp(("t"."RollupType")::double precision)))) / 86400) END)", } `; @@ -7574,12 +8409,17 @@ exports[`date functions batch 2 > 'ToNow' with 'singleLineText' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + "sql": "CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END ELSE ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz - END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END)))) / 86400) END))::text END", + END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END))))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT "t"."SingleLineText" AS val) AS v) END)))) / 86400) END) END))::text END", } `; @@ -7598,7 +8438,7 @@ exports[`date functions batch 2 > 'ToNow' with 'singleSelect' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7617,7 +8457,7 @@ exports[`date functions batch 2 > 'ToNow' with 'user' 1`] = ` }, }, "result": "#ERROR:TYPE:cannot_cast_to_datetime", - "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE TRUNC((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END))::text END", + "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ABS((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz)))) < 1 THEN 0::double precision ELSE ((EXTRACT(EPOCH FROM (NOW() - NULL::timestamptz))) / 86400) END) END))::text END", } `; @@ -7886,8 +8726,8 @@ exports[`date functions batch 2 > 'Workday' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8407,8 +9247,8 @@ exports[`date functions batch 2 > 'Workday' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8427,8 +9267,8 @@ exports[`date functions batch 2 > 'Workday' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8447,8 +9287,8 @@ exports[`date functions batch 2 > 'Workday' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8467,8 +9307,8 @@ exports[`date functions batch 2 > 'Workday' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8516,8 +9356,8 @@ exports[`date functions batch 2 > 'Workday' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8541,8 +9381,8 @@ exports[`date functions batch 2 > 'Workday' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9029,8 +9869,8 @@ exports[`date functions batch 3 > 'DateAdd' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9269,8 +10109,8 @@ exports[`date functions batch 3 > 'DateAdd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9289,8 +10129,8 @@ exports[`date functions batch 3 > 'DateAdd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9309,8 +10149,8 @@ exports[`date functions batch 3 > 'DateAdd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9329,8 +10169,8 @@ exports[`date functions batch 3 > 'DateAdd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9349,8 +10189,8 @@ exports[`date functions batch 3 > 'DateAdd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9374,8 +10214,8 @@ exports[`date functions batch 3 > 'DateAdd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9700,8 +10540,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9720,8 +10560,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9740,8 +10580,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9760,8 +10600,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9784,8 +10624,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9808,8 +10648,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9829,8 +10669,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9849,8 +10689,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9913,9 +10753,9 @@ exports[`date functions batch 3 > 'IsAfter' with 'createdBy' 1`] = ` "result": "#ERROR:TYPE:cannot_cast_to_datetime", "sql": "CASE WHEN TRUE THEN CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:invalid_comparison' END ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ((SELECT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp')) FROM (SELECT (NULL::timestamptz)::text AS val) AS v) AND (SELECT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp')) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v)) THEN ((SELECT (CASE WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -9925,14 +10765,14 @@ exports[`date functions batch 3 > 'IsAfter' with 'createdBy' 1`] = ` WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v)) ELSE (COALESCE((NULL::timestamptz)::text, '') > COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '')) END) END))::text END", } @@ -10056,9 +10896,9 @@ exports[`date functions batch 3 > 'IsAfter' with 'lastModifiedBy' 1`] = ` "result": "#ERROR:TYPE:cannot_cast_to_datetime", "sql": "CASE WHEN TRUE THEN CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:invalid_comparison' END ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ((SELECT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp')) FROM (SELECT (NULL::timestamptz)::text AS val) AS v) AND (SELECT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp')) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v)) THEN ((SELECT (CASE WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' @@ -10068,14 +10908,14 @@ exports[`date functions batch 3 > 'IsAfter' with 'lastModifiedBy' 1`] = ` WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v)) ELSE (COALESCE((NULL::timestamptz)::text, '') > COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '')) END) END))::text END", } @@ -10223,8 +11063,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10243,8 +11083,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10263,8 +11103,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10283,8 +11123,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10303,8 +11143,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10324,8 +11164,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10344,8 +11184,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10369,8 +11209,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10389,8 +11229,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10413,8 +11253,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10433,8 +11273,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10458,8 +11298,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10482,8 +11322,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10503,8 +11343,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10523,8 +11363,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10548,8 +11388,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10568,8 +11408,8 @@ exports[`date functions batch 3 > 'IsAfter' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11006,8 +11846,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11026,8 +11866,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11046,8 +11886,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11066,8 +11906,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11090,8 +11930,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11114,8 +11954,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11135,8 +11975,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11155,8 +11995,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11219,26 +12059,26 @@ exports[`date functions batch 3 > 'IsBefore' with 'createdBy' 1`] = ` "result": "#ERROR:TYPE:cannot_cast_to_datetime", "sql": "CASE WHEN TRUE THEN CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:invalid_comparison' END ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ((SELECT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp')) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) AND (SELECT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp')) FROM (SELECT (NULL::timestamptz)::text AS val) AS v)) THEN ((SELECT (CASE WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) < (SELECT (CASE WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL END) FROM (SELECT (NULL::timestamptz)::text AS val) AS v)) ELSE (COALESCE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '') < COALESCE((NULL::timestamptz)::text, '')) END) END))::text END", } @@ -11362,26 +12202,26 @@ exports[`date functions batch 3 > 'IsBefore' with 'lastModifiedBy' 1`] = ` "result": "#ERROR:TYPE:cannot_cast_to_datetime", "sql": "CASE WHEN TRUE THEN CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:invalid_comparison' END ELSE ((CASE WHEN TRUE THEN NULL ELSE (CASE WHEN ((SELECT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp')) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) AND (SELECT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp')) FROM (SELECT (NULL::timestamptz)::text AS val) AS v)) THEN ((SELECT (CASE WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) < (SELECT (CASE WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL END) FROM (SELECT (NULL::timestamptz)::text AS val) AS v)) ELSE (COALESCE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '') < COALESCE((NULL::timestamptz)::text, '')) END) END))::text END", } @@ -11529,8 +12369,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11549,8 +12389,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11569,8 +12409,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11589,8 +12429,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11609,8 +12449,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11630,8 +12470,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11650,8 +12490,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11670,8 +12510,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11695,8 +12535,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11719,8 +12559,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11743,8 +12583,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11763,8 +12603,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11788,8 +12628,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11809,8 +12649,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11829,8 +12669,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11849,8 +12689,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11874,8 +12714,8 @@ exports[`date functions batch 3 > 'IsBefore' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12255,8 +13095,8 @@ exports[`date functions batch 3 > 'IsSame' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -12275,8 +13115,8 @@ exports[`date functions batch 3 > 'IsSame' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -12520,8 +13360,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12540,8 +13380,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12560,8 +13400,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12580,8 +13420,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12600,8 +13440,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12620,8 +13460,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12640,8 +13480,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12660,8 +13500,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12680,8 +13520,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12700,8 +13540,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12725,8 +13565,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12745,8 +13585,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12765,8 +13605,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12790,8 +13630,8 @@ exports[`date functions batch 3 > 'IsSame' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -13701,7 +14541,7 @@ exports[`date functions batch 3 > 'IsSameUnitField' with 'longText' 1`] = ` }, }, "result": "#ERROR:ARG:invalid_is_same_unit", - "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'month', 'months', 'day', 'days'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'month', 'months', 'day', 'days')) THEN '#ERROR:ARG:invalid_is_same_unit' ELSE '#ERROR:ARG:invalid_is_same_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'month', 'months', 'day', 'days'))) THEN NULL ELSE (CASE + "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'h', 'hr', 'hrs', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'h', 'hr', 'hrs', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs')) THEN '#ERROR:ARG:invalid_is_same_unit' ELSE '#ERROR:ARG:invalid_is_same_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'h', 'hr', 'hrs', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs'))) THEN NULL ELSE (CASE WHEN LOWER("t"."LongText") IN ('year', 'years') THEN DATE_TRUNC('year', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz @@ -13724,6 +14564,17 @@ exports[`date functions batch 3 > 'IsSameUnitField' with 'longText' 1`] = ` WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + WHEN LOWER("t"."LongText") IN ('week', 'weeks') THEN DATE_TRUNC('week', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') = DATE_TRUNC('week', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') WHEN LOWER("t"."LongText") IN ('day', 'days') THEN DATE_TRUNC('day', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz @@ -13735,6 +14586,39 @@ exports[`date functions batch 3 > 'IsSameUnitField' with 'longText' 1`] = ` WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + WHEN LOWER("t"."LongText") IN ('hour', 'hours', 'h', 'hr', 'hrs') THEN DATE_TRUNC('hour', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') = DATE_TRUNC('hour', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + WHEN LOWER("t"."LongText") IN ('minute', 'minutes', 'min', 'mins') THEN DATE_TRUNC('minute', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') = DATE_TRUNC('minute', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + WHEN LOWER("t"."LongText") IN ('second', 'seconds', 's', 'sec', 'secs') THEN DATE_TRUNC('second', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') = DATE_TRUNC('second', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') ELSE NULL END) END))::text END", } @@ -13863,7 +14747,7 @@ exports[`date functions batch 3 > 'IsSameUnitField' with 'singleLineText' 1`] = }, }, "result": "#ERROR:ARG:invalid_is_same_unit", - "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'month', 'months', 'day', 'days'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'month', 'months', 'day', 'days')) THEN '#ERROR:ARG:invalid_is_same_unit' ELSE '#ERROR:ARG:invalid_is_same_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'month', 'months', 'day', 'days'))) THEN NULL ELSE (CASE + "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'h', 'hr', 'hrs', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'h', 'hr', 'hrs', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs')) THEN '#ERROR:ARG:invalid_is_same_unit' ELSE '#ERROR:ARG:invalid_is_same_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'h', 'hr', 'hrs', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs'))) THEN NULL ELSE (CASE WHEN LOWER("t"."SingleLineText") IN ('year', 'years') THEN DATE_TRUNC('year', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz @@ -13886,6 +14770,17 @@ exports[`date functions batch 3 > 'IsSameUnitField' with 'singleLineText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + WHEN LOWER("t"."SingleLineText") IN ('week', 'weeks') THEN DATE_TRUNC('week', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') = DATE_TRUNC('week', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') WHEN LOWER("t"."SingleLineText") IN ('day', 'days') THEN DATE_TRUNC('day', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz @@ -13897,6 +14792,39 @@ exports[`date functions batch 3 > 'IsSameUnitField' with 'singleLineText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + WHEN LOWER("t"."SingleLineText") IN ('hour', 'hours', 'h', 'hr', 'hrs') THEN DATE_TRUNC('hour', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') = DATE_TRUNC('hour', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + WHEN LOWER("t"."SingleLineText") IN ('minute', 'minutes', 'min', 'mins') THEN DATE_TRUNC('minute', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') = DATE_TRUNC('minute', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') + WHEN LOWER("t"."SingleLineText") IN ('second', 'seconds', 's', 'sec', 'secs') THEN DATE_TRUNC('second', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') = DATE_TRUNC('second', ((CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-03T00:00:00Z' AS val) AS v) END)) AT TIME ZONE 'UTC') ELSE NULL END) END))::text END", } @@ -14647,8 +15575,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14667,8 +15595,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14687,8 +15615,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14707,8 +15635,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14727,8 +15655,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14747,8 +15675,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14767,8 +15695,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14787,8 +15715,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14807,8 +15735,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14829,8 +15757,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14854,8 +15782,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14874,8 +15802,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14894,8 +15822,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -14919,8 +15847,8 @@ exports[`date functions batch 3 > 'WorkdayDiff' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -15424,8 +16352,8 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'conditionalLookup' 1 ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -15480,38 +16408,38 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v)) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:invalid_date_add' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v)) THEN NULL ELSE (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)) * INTERVAL '1 day' END))::text END", } `; @@ -15605,38 +16533,38 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'lastModifiedBy' 1`] }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v)) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:invalid_date_add' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v)) THEN NULL ELSE (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)) * INTERVAL '1 day' END))::text END", } `; @@ -15744,8 +16672,8 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -15764,8 +16692,8 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -15784,8 +16712,8 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -15804,8 +16732,8 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -15829,8 +16757,8 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -15853,8 +16781,8 @@ exports[`date functions batch 4 > 'DateAddCountField' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -16853,7 +17781,13 @@ exports[`date functions batch 4 > 'DateAddUnitField' with 'longText' 1`] = ` }, }, "result": "#ERROR:ARG:invalid_date_add_unit", - "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'second', 'seconds'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'second', 'seconds')) THEN '#ERROR:ARG:invalid_date_add_unit' ELSE '#ERROR:ARG:invalid_date_add_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'second', 'seconds'))) THEN NULL ELSE (CASE + "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'ms', 'year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs', 'h', 'hr', 'hrs'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'ms', 'year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs', 'h', 'hr', 'hrs')) THEN '#ERROR:ARG:invalid_date_add_unit' ELSE '#ERROR:ARG:invalid_date_add_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (LOWER("t"."LongText") IS NULL OR LOWER("t"."LongText") NOT IN ('millisecond', 'milliseconds', 'ms', 'year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs', 'h', 'hr', 'hrs'))) THEN NULL ELSE (CASE + WHEN LOWER("t"."LongText") IN ('millisecond', 'milliseconds', 'ms') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 millisecond' WHEN LOWER("t"."LongText") IN ('year', 'years') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz @@ -16896,12 +17830,30 @@ exports[`date functions batch 4 > 'DateAddUnitField' with 'longText' 1`] = ` WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 minute' + WHEN LOWER("t"."LongText") IN ('min', 'mins') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 minute' WHEN LOWER("t"."LongText") IN ('second', 'seconds') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 second' + WHEN LOWER("t"."LongText") IN ('s', 'sec', 'secs') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 second' + WHEN LOWER("t"."LongText") IN ('h', 'hr', 'hrs') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 hour' ELSE NULL::timestamptz END) END))::text END", } @@ -17030,7 +17982,13 @@ exports[`date functions batch 4 > 'DateAddUnitField' with 'singleLineText' 1`] = }, }, "result": "#ERROR:ARG:invalid_date_add_unit", - "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'second', 'seconds'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'second', 'seconds')) THEN '#ERROR:ARG:invalid_date_add_unit' ELSE '#ERROR:ARG:invalid_date_add_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'second', 'seconds'))) THEN NULL ELSE (CASE + "sql": "CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'ms', 'year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs', 'h', 'hr', 'hrs'))) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_datetime' ELSE '#ERROR:TYPE:cannot_cast_to_datetime' END WHEN (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'ms', 'year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs', 'h', 'hr', 'hrs')) THEN '#ERROR:ARG:invalid_date_add_unit' ELSE '#ERROR:ARG:invalid_date_add_unit' END ELSE ((CASE WHEN ((SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) OR (LOWER("t"."SingleLineText") IS NULL OR LOWER("t"."SingleLineText") NOT IN ('millisecond', 'milliseconds', 'ms', 'year', 'years', 'quarter', 'quarters', 'month', 'months', 'week', 'weeks', 'day', 'days', 'hour', 'hours', 'minute', 'minutes', 'min', 'mins', 'second', 'seconds', 's', 'sec', 'secs', 'h', 'hr', 'hrs'))) THEN NULL ELSE (CASE + WHEN LOWER("t"."SingleLineText") IN ('millisecond', 'milliseconds', 'ms') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 millisecond' WHEN LOWER("t"."SingleLineText") IN ('year', 'years') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz @@ -17073,12 +18031,30 @@ exports[`date functions batch 4 > 'DateAddUnitField' with 'singleLineText' 1`] = WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 minute' + WHEN LOWER("t"."SingleLineText") IN ('min', 'mins') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 minute' WHEN LOWER("t"."SingleLineText") IN ('second', 'seconds') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN v.val IS NULL THEN NULL::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' ELSE NULL::timestamptz END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 second' + WHEN LOWER("t"."SingleLineText") IN ('s', 'sec', 'secs') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 second' + WHEN LOWER("t"."SingleLineText") IN ('h', 'hr', 'hrs') THEN (CASE WHEN (SELECT (v.val IS NOT NULL AND NOT (__teable_input_is_valid((v.val)::text, 'timestamptz') OR __teable_input_is_valid((v.val)::text, 'timestamp'))) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) THEN NULL ELSE (SELECT (CASE + WHEN v.val IS NULL THEN NULL::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamptz') THEN ((v.val)::text)::timestamptz + WHEN __teable_input_is_valid((v.val)::text, 'timestamp') THEN ((v.val)::text)::timestamp AT TIME ZONE 'UTC' + ELSE NULL::timestamptz + END) FROM (SELECT '2024-01-02T00:00:00Z' AS val) AS v) END) + ((1)::double precision) * INTERVAL '1 hour' ELSE NULL::timestamptz END) END))::text END", } @@ -17269,8 +18245,8 @@ exports[`date functions batch 4 > 'Datestr' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -17525,8 +18501,8 @@ exports[`date functions batch 4 > 'Datestr' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -17974,8 +18950,8 @@ exports[`date functions batch 4 > 'DatetimeFormat' with 'conditionalLookup' 1`] ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18302,8 +19278,8 @@ exports[`date functions batch 4 > 'DatetimeFormat' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -18746,8 +19722,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18765,8 +19741,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18784,8 +19760,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18803,8 +19779,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18822,8 +19798,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18841,8 +19817,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18860,8 +19836,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18879,8 +19855,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18898,8 +19874,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18918,8 +19894,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18938,8 +19914,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18957,8 +19933,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18976,8 +19952,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -18995,8 +19971,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -19015,8 +19991,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -19034,8 +20010,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -19054,8 +20030,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -19073,8 +20049,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'conditionalLookup' 1`] = ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -19327,8 +20303,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19346,8 +20322,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19365,8 +20341,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19384,8 +20360,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19403,8 +20379,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19422,8 +20398,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19441,8 +20417,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19460,8 +20436,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19479,8 +20455,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19499,8 +20475,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19519,8 +20495,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19538,8 +20514,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19557,8 +20533,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19576,8 +20552,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19596,8 +20572,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19615,8 +20591,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19635,8 +20611,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19654,8 +20630,8 @@ exports[`date functions batch 4 > 'DatetimeParse' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -19980,8 +20956,8 @@ exports[`date functions batch 4 > 'Timestr' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -20236,8 +21212,8 @@ exports[`date functions batch 4 > 'Timestr' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL diff --git a/packages/v2/formula-sql-pg/src/__snapshots__/IfBranchNormalization.spec.ts.snap b/packages/v2/formula-sql-pg/src/__snapshots__/IfBranchNormalization.spec.ts.snap index 3fb9995eb..79817df66 100644 --- a/packages/v2/formula-sql-pg/src/__snapshots__/IfBranchNormalization.spec.ts.snap +++ b/packages/v2/formula-sql-pg/src/__snapshots__/IfBranchNormalization.spec.ts.snap @@ -37,8 +37,8 @@ exports[`if branch normalization > 'IfEmptyTextThenLookup' snapshots 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -92,8 +92,8 @@ exports[`if branch normalization > 'IfLookupThenEmptyText' snapshots 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL diff --git a/packages/v2/formula-sql-pg/src/__snapshots__/LogicalFunctions.spec.ts.snap b/packages/v2/formula-sql-pg/src/__snapshots__/LogicalFunctions.spec.ts.snap index c04dc7f2c..ebd169dd8 100644 --- a/packages/v2/formula-sql-pg/src/__snapshots__/LogicalFunctions.spec.ts.snap +++ b/packages/v2/formula-sql-pg/src/__snapshots__/LogicalFunctions.spec.ts.snap @@ -118,8 +118,8 @@ exports[`logical functions > 'And' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -134,8 +134,8 @@ exports[`logical functions > 'And' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -151,8 +151,8 @@ exports[`logical functions > 'And' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -167,8 +167,8 @@ exports[`logical functions > 'And' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -221,19 +221,19 @@ exports[`logical functions > 'And' with 'createdBy' 1`] = ` "result": "true", "sql": "((CASE WHEN (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END) AND COALESCE(TRUE, FALSE))", @@ -335,19 +335,19 @@ exports[`logical functions > 'And' with 'lastModifiedBy' 1`] = ` "result": "true", "sql": "((CASE WHEN (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END) AND COALESCE(TRUE, FALSE))", @@ -460,8 +460,8 @@ exports[`logical functions > 'And' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -476,8 +476,8 @@ exports[`logical functions > 'And' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -493,8 +493,8 @@ exports[`logical functions > 'And' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -509,8 +509,8 @@ exports[`logical functions > 'And' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -858,8 +858,8 @@ exports[`logical functions > 'If' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -874,8 +874,8 @@ exports[`logical functions > 'If' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -891,8 +891,8 @@ exports[`logical functions > 'If' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -907,8 +907,8 @@ exports[`logical functions > 'If' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -961,19 +961,19 @@ exports[`logical functions > 'If' with 'createdBy' 1`] = ` "result": "yes", "sql": "(CASE WHEN (CASE WHEN (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END) THEN 'yes' ELSE 'no' END)", @@ -1075,19 +1075,19 @@ exports[`logical functions > 'If' with 'lastModifiedBy' 1`] = ` "result": "yes", "sql": "(CASE WHEN (CASE WHEN (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END) THEN 'yes' ELSE 'no' END)", @@ -1200,8 +1200,8 @@ exports[`logical functions > 'If' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1216,8 +1216,8 @@ exports[`logical functions > 'If' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1233,8 +1233,8 @@ exports[`logical functions > 'If' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1249,8 +1249,8 @@ exports[`logical functions > 'If' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1534,8 +1534,8 @@ exports[`logical functions > 'IsError' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -1586,9 +1586,9 @@ exports[`logical functions > 'IsError' with 'createdBy' 1`] = ` }, "result": "false", "sql": "((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) LIKE '#ERROR:%')", } `; @@ -1677,9 +1677,9 @@ exports[`logical functions > 'IsError' with 'lastModifiedBy' 1`] = ` }, "result": "false", "sql": "((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) LIKE '#ERROR:%')", } `; @@ -1776,8 +1776,8 @@ exports[`logical functions > 'IsError' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2053,8 +2053,8 @@ exports[`logical functions > 'Not' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2069,8 +2069,8 @@ exports[`logical functions > 'Not' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2086,8 +2086,8 @@ exports[`logical functions > 'Not' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2102,8 +2102,8 @@ exports[`logical functions > 'Not' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2156,19 +2156,19 @@ exports[`logical functions > 'Not' with 'createdBy' 1`] = ` "result": "false", "sql": "(NOT (CASE WHEN (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END))", @@ -2270,19 +2270,19 @@ exports[`logical functions > 'Not' with 'lastModifiedBy' 1`] = ` "result": "false", "sql": "(NOT (CASE WHEN (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END))", @@ -2395,8 +2395,8 @@ exports[`logical functions > 'Not' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2411,8 +2411,8 @@ exports[`logical functions > 'Not' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2428,8 +2428,8 @@ exports[`logical functions > 'Not' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2444,8 +2444,8 @@ exports[`logical functions > 'Not' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2734,8 +2734,8 @@ exports[`logical functions > 'Or' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2750,8 +2750,8 @@ exports[`logical functions > 'Or' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2767,8 +2767,8 @@ exports[`logical functions > 'Or' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2783,8 +2783,8 @@ exports[`logical functions > 'Or' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2837,19 +2837,19 @@ exports[`logical functions > 'Or' with 'createdBy' 1`] = ` "result": "true", "sql": "((CASE WHEN (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END) OR COALESCE(FALSE, FALSE))", @@ -2951,19 +2951,19 @@ exports[`logical functions > 'Or' with 'lastModifiedBy' 1`] = ` "result": "true", "sql": "((CASE WHEN (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END) OR COALESCE(FALSE, FALSE))", @@ -3076,8 +3076,8 @@ exports[`logical functions > 'Or' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3092,8 +3092,8 @@ exports[`logical functions > 'Or' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3109,8 +3109,8 @@ exports[`logical functions > 'Or' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3125,8 +3125,8 @@ exports[`logical functions > 'Or' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3410,8 +3410,8 @@ exports[`logical functions > 'Switch' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3462,9 +3462,9 @@ exports[`logical functions > 'Switch' with 'createdBy' 1`] = ` }, "result": "other", "sql": "(CASE WHEN (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) = (10)::text THEN 'ten' ELSE 'other' END)", } `; @@ -3553,9 +3553,9 @@ exports[`logical functions > 'Switch' with 'lastModifiedBy' 1`] = ` }, "result": "other", "sql": "(CASE WHEN (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) = (10)::text THEN 'ten' ELSE 'other' END)", } `; @@ -3652,8 +3652,8 @@ exports[`logical functions > 'Switch' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3929,8 +3929,8 @@ exports[`logical functions > 'Xor' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3945,8 +3945,8 @@ exports[`logical functions > 'Xor' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3962,8 +3962,8 @@ exports[`logical functions > 'Xor' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3978,8 +3978,8 @@ exports[`logical functions > 'Xor' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -4032,19 +4032,19 @@ exports[`logical functions > 'Xor' with 'createdBy' 1`] = ` "result": "false", "sql": "(((CASE WHEN (CASE WHEN (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END) THEN 1 ELSE 0 END) + (CASE WHEN COALESCE(TRUE, FALSE) THEN 1 ELSE 0 END)) % 2 = 1)", @@ -4146,19 +4146,19 @@ exports[`logical functions > 'Xor' with 'lastModifiedBy' 1`] = ` "result": "false", "sql": "(((CASE WHEN (CASE WHEN (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) IS NULL THEN FALSE WHEN BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END)) = '' THEN FALSE WHEN LOWER(BTRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))) IN ('false','0','no','off','null') THEN FALSE ELSE TRUE END) THEN 1 ELSE 0 END) + (CASE WHEN COALESCE(TRUE, FALSE) THEN 1 ELSE 0 END)) % 2 = 1)", @@ -4271,8 +4271,8 @@ exports[`logical functions > 'Xor' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4287,8 +4287,8 @@ exports[`logical functions > 'Xor' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4304,8 +4304,8 @@ exports[`logical functions > 'Xor' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4320,8 +4320,8 @@ exports[`logical functions > 'Xor' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL diff --git a/packages/v2/formula-sql-pg/src/__snapshots__/NumericFunctions.spec.ts.snap b/packages/v2/formula-sql-pg/src/__snapshots__/NumericFunctions.spec.ts.snap index 2922a09be..e25ada24f 100644 --- a/packages/v2/formula-sql-pg/src/__snapshots__/NumericFunctions.spec.ts.snap +++ b/packages/v2/formula-sql-pg/src/__snapshots__/NumericFunctions.spec.ts.snap @@ -136,8 +136,8 @@ exports[`numeric functions > 'Abs' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -187,29 +187,29 @@ exports[`numeric functions > 'Abs' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE ABS((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -298,29 +298,29 @@ exports[`numeric functions > 'Abs' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE ABS((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -423,8 +423,8 @@ exports[`numeric functions > 'Abs' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -443,8 +443,8 @@ exports[`numeric functions > 'Abs' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -463,8 +463,8 @@ exports[`numeric functions > 'Abs' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -483,8 +483,8 @@ exports[`numeric functions > 'Abs' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -507,8 +507,8 @@ exports[`numeric functions > 'Abs' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -850,8 +850,8 @@ exports[`numeric functions > 'Average' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -867,8 +867,8 @@ exports[`numeric functions > 'Average' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -918,33 +918,33 @@ exports[`numeric functions > 'Average' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (CASE WHEN 2 = 0 THEN NULL ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END) + (2)::double precision) / 2 END) END))::text END", } `; @@ -1033,33 +1033,33 @@ exports[`numeric functions > 'Average' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (CASE WHEN 2 = 0 THEN NULL ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END) + (2)::double precision) / 2 END) END))::text END", } `; @@ -1171,8 +1171,8 @@ exports[`numeric functions > 'Average' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1188,8 +1188,8 @@ exports[`numeric functions > 'Average' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1423,23 +1423,23 @@ exports[`numeric functions > 'Ceiling' with 'attachment' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -1527,23 +1527,23 @@ exports[`numeric functions > 'Ceiling' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN NULL ELSE CEIL((CASE + WHEN elem IS NULL OR jsonb_typeof(elem) = 'null' THEN NULL::double precision + WHEN __teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL - WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision - ELSE NULL - END) FROM (SELECT ((CASE + END))::text, 'numeric') THEN (((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END))::text)::double precision + ELSE NULL::double precision + END)) END)) ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -1551,8 +1551,8 @@ exports[`numeric functions > 'Ceiling' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -1603,29 +1603,29 @@ exports[`numeric functions > 'Ceiling' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -1714,29 +1714,29 @@ exports[`numeric functions > 'Ceiling' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -1828,23 +1828,23 @@ exports[`numeric functions > 'Ceiling' with 'lookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -1852,8 +1852,8 @@ exports[`numeric functions > 'Ceiling' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1881,23 +1881,23 @@ exports[`numeric functions > 'Ceiling' with 'multipleSelect' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -2027,23 +2027,23 @@ exports[`numeric functions > 'Ceiling' with 'user' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -2087,9 +2087,8 @@ exports[`numeric functions > 'Even' with 'attachment' 1`] = ` ELSE COALESCE(fe.elem->>'title', fe.elem->>'name', fe.elem #>> '{}') END FROM (SELECT (COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb) -> 0) AS elem) AS fe) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (SELECT CASE WHEN fe.elem IS NULL OR jsonb_typeof(fe.elem) = 'null' THEN NULL ELSE COALESCE(fe.elem->>'title', fe.elem->>'name', fe.elem #>> '{}') @@ -2122,9 +2121,8 @@ exports[`numeric functions > 'Even' with 'autoNumber' 1`] = ` }, "result": "2", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."AutoNumber")::double precision AS val) AS v)", } `; @@ -2145,9 +2143,8 @@ exports[`numeric functions > 'Even' with 'button' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -2168,9 +2165,8 @@ exports[`numeric functions > 'Even' with 'checkbox' 1`] = ` }, "result": "2", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN "t"."Checkbox" IS NULL THEN NULL WHEN "t"."Checkbox" THEN 1 ELSE 0 END)::double precision AS val) AS v)", } `; @@ -2201,9 +2197,8 @@ exports[`numeric functions > 'Even' with 'conditionalLookup' 1`] = ` }, "result": null, "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ((SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE (lkp.elem #>> '{}')::numeric @@ -2215,8 +2210,8 @@ exports[`numeric functions > 'Even' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2247,9 +2242,8 @@ exports[`numeric functions > 'Even' with 'conditionalRollup' 1`] = ` }, "result": null, "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."ConditionalRollupType")::double precision AS val) AS v)", } `; @@ -2270,33 +2264,32 @@ exports[`numeric functions > 'Even' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END) AS val) AS v) END))::text END", } `; @@ -2321,9 +2314,8 @@ exports[`numeric functions > 'Even' with 'createdTime' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_datetime_to_number_even", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_datetime_to_number_even' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -2348,9 +2340,8 @@ exports[`numeric functions > 'Even' with 'date' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_datetime_to_number_even", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_datetime_to_number_even' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -2374,9 +2365,8 @@ exports[`numeric functions > 'Even' with 'formula' 1`] = ` }, "result": "10", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (10)::double precision AS val) AS v)", } `; @@ -2397,33 +2387,32 @@ exports[`numeric functions > 'Even' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END) AS val) AS v) END))::text END", } `; @@ -2448,9 +2437,8 @@ exports[`numeric functions > 'Even' with 'lastModifiedTime' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_datetime_to_number_even", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_datetime_to_number_even' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -2471,9 +2459,8 @@ exports[`numeric functions > 'Even' with 'link' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -2494,9 +2481,8 @@ exports[`numeric functions > 'Even' with 'longText' 1`] = ` }, "result": "10", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision @@ -2538,8 +2524,8 @@ exports[`numeric functions > 'Even' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2558,8 +2544,8 @@ exports[`numeric functions > 'Even' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2578,8 +2564,8 @@ exports[`numeric functions > 'Even' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2588,9 +2574,8 @@ exports[`numeric functions > 'Even' with 'lookup' 1`] = ` END ELSE to_jsonb((("t"."LookupType"))) END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE lkp.elem #>> '{}' @@ -2602,8 +2587,8 @@ exports[`numeric functions > 'Even' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2626,8 +2611,8 @@ exports[`numeric functions > 'Even' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2667,9 +2652,8 @@ exports[`numeric functions > 'Even' with 'multipleSelect' 1`] = ` ELSE fe.elem #>> '{}' END FROM (SELECT (COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb) -> 0) AS elem) AS fe) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (SELECT CASE WHEN fe.elem IS NULL OR jsonb_typeof(fe.elem) = 'null' THEN NULL ELSE fe.elem #>> '{}' @@ -2705,9 +2689,8 @@ exports[`numeric functions > 'Even' with 'number' 1`] = ` }, "result": "10", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."Number")::double precision AS val) AS v)", } `; @@ -2728,9 +2711,8 @@ exports[`numeric functions > 'Even' with 'rating' 1`] = ` }, "result": "4", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."Rating")::double precision AS val) AS v)", } `; @@ -2754,9 +2736,8 @@ exports[`numeric functions > 'Even' with 'rollup' 1`] = ` }, "result": null, "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."RollupType")::double precision AS val) AS v)", } `; @@ -2777,9 +2758,8 @@ exports[`numeric functions > 'Even' with 'singleLineText' 1`] = ` }, "result": "10", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision @@ -2804,9 +2784,8 @@ exports[`numeric functions > 'Even' with 'singleSelect' 1`] = ` }, "result": "10", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleSelect" AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleSelect" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleSelect" AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleSelect" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision @@ -2843,9 +2822,8 @@ exports[`numeric functions > 'Even' with 'user' 1`] = ` ELSE COALESCE(fe.elem->>'title', fe.elem->>'name', fe.elem #>> '{}') END FROM (SELECT (COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb) -> 0) AS elem) AS fe) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) = 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) > 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) = 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (SELECT CASE WHEN fe.elem IS NULL OR jsonb_typeof(fe.elem) = 'null' THEN NULL ELSE COALESCE(fe.elem->>'title', fe.elem->>'name', fe.elem #>> '{}') @@ -2998,8 +2976,8 @@ exports[`numeric functions > 'Exp' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3049,29 +3027,29 @@ exports[`numeric functions > 'Exp' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE EXP((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -3160,29 +3138,29 @@ exports[`numeric functions > 'Exp' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE EXP((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -3285,8 +3263,8 @@ exports[`numeric functions > 'Exp' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3305,8 +3283,8 @@ exports[`numeric functions > 'Exp' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3325,8 +3303,8 @@ exports[`numeric functions > 'Exp' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3345,8 +3323,8 @@ exports[`numeric functions > 'Exp' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3369,8 +3347,8 @@ exports[`numeric functions > 'Exp' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3592,23 +3570,23 @@ exports[`numeric functions > 'Floor' with 'attachment' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -3696,23 +3674,23 @@ exports[`numeric functions > 'Floor' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN NULL ELSE FLOOR((CASE + WHEN elem IS NULL OR jsonb_typeof(elem) = 'null' THEN NULL::double precision + WHEN __teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL - WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision - ELSE NULL - END) FROM (SELECT ((CASE + END))::text, 'numeric') THEN (((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END))::text)::double precision + ELSE NULL::double precision + END)) END)) ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -3720,8 +3698,8 @@ exports[`numeric functions > 'Floor' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3772,29 +3750,29 @@ exports[`numeric functions > 'Floor' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -3883,29 +3861,29 @@ exports[`numeric functions > 'Floor' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -3997,23 +3975,23 @@ exports[`numeric functions > 'Floor' with 'lookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -4021,8 +3999,8 @@ exports[`numeric functions > 'Floor' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4050,23 +4028,23 @@ exports[`numeric functions > 'Floor' with 'multipleSelect' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -4196,23 +4174,23 @@ exports[`numeric functions > 'Floor' with 'user' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -4233,23 +4211,23 @@ exports[`numeric functions > 'Int' with 'attachment' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -4337,23 +4315,23 @@ exports[`numeric functions > 'Int' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN NULL ELSE FLOOR((CASE + WHEN elem IS NULL OR jsonb_typeof(elem) = 'null' THEN NULL::double precision + WHEN __teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL - WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision - ELSE NULL - END) FROM (SELECT ((CASE + END))::text, 'numeric') THEN (((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END))::text)::double precision + ELSE NULL::double precision + END)) END)) ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -4361,8 +4339,8 @@ exports[`numeric functions > 'Int' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -4413,29 +4391,29 @@ exports[`numeric functions > 'Int' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -4524,29 +4502,29 @@ exports[`numeric functions > 'Int' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -4638,23 +4616,23 @@ exports[`numeric functions > 'Int' with 'lookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -4662,8 +4640,8 @@ exports[`numeric functions > 'Int' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4691,23 +4669,23 @@ exports[`numeric functions > 'Int' with 'multipleSelect' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -4837,23 +4815,23 @@ exports[`numeric functions > 'Int' with 'user' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)) END)) ORDER BY ord) + END) AS val) AS v) END)) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -4999,8 +4977,8 @@ exports[`numeric functions > 'Log' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -5050,33 +5028,33 @@ exports[`numeric functions > 'Log' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (LN((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)) / NULLIF(LN((10)::double precision), 0)) END))::text END", } `; @@ -5165,33 +5143,33 @@ exports[`numeric functions > 'Log' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (LN((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)) / NULLIF(LN((10)::double precision), 0)) END))::text END", } `; @@ -5294,8 +5272,8 @@ exports[`numeric functions > 'Log' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -5314,8 +5292,8 @@ exports[`numeric functions > 'Log' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -5334,8 +5312,8 @@ exports[`numeric functions > 'Log' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -5354,8 +5332,8 @@ exports[`numeric functions > 'Log' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -5374,8 +5352,8 @@ exports[`numeric functions > 'Log' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -5398,8 +5376,8 @@ exports[`numeric functions > 'Log' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -5770,8 +5748,8 @@ exports[`numeric functions > 'Max' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -5822,33 +5800,33 @@ exports[`numeric functions > 'Max' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE GREATEST((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END), (2)::double precision) END))::text END", } `; @@ -5937,33 +5915,33 @@ exports[`numeric functions > 'Max' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE GREATEST((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END), (2)::double precision) END))::text END", } `; @@ -6075,8 +6053,8 @@ exports[`numeric functions > 'Max' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6431,8 +6409,8 @@ exports[`numeric functions > 'Min' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6483,33 +6461,33 @@ exports[`numeric functions > 'Min' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE LEAST((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END), (2)::double precision) END))::text END", } `; @@ -6598,33 +6576,33 @@ exports[`numeric functions > 'Min' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE LEAST((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END), (2)::double precision) END))::text END", } `; @@ -6736,8 +6714,8 @@ exports[`numeric functions > 'Min' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7097,8 +7075,8 @@ exports[`numeric functions > 'Mod' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -7148,33 +7126,33 @@ exports[`numeric functions > 'Mod' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN ((SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) OR ((2)::double precision) = 0) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END WHEN ((2)::double precision) = 0 THEN '#ERROR:DIV0:division_by_zero' ELSE '#ERROR:DIV0:division_by_zero' END ELSE ((CASE WHEN ((SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) OR ((2)::double precision) = 0) THEN NULL ELSE MOD((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)::numeric, (2)::double precision::numeric)::double precision END))::text END", } `; @@ -7263,33 +7241,33 @@ exports[`numeric functions > 'Mod' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN ((SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) OR ((2)::double precision) = 0) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END WHEN ((2)::double precision) = 0 THEN '#ERROR:DIV0:division_by_zero' ELSE '#ERROR:DIV0:division_by_zero' END ELSE ((CASE WHEN ((SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) OR ((2)::double precision) = 0) THEN NULL ELSE MOD((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)::numeric, (2)::double precision::numeric)::double precision END))::text END", } `; @@ -7392,8 +7370,8 @@ exports[`numeric functions > 'Mod' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7412,8 +7390,8 @@ exports[`numeric functions > 'Mod' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7432,8 +7410,8 @@ exports[`numeric functions > 'Mod' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7452,8 +7430,8 @@ exports[`numeric functions > 'Mod' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7472,8 +7450,8 @@ exports[`numeric functions > 'Mod' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7496,8 +7474,8 @@ exports[`numeric functions > 'Mod' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7740,9 +7718,8 @@ exports[`numeric functions > 'Odd' with 'attachment' 1`] = ` ELSE COALESCE(fe.elem->>'title', fe.elem->>'name', fe.elem #>> '{}') END FROM (SELECT (COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb) -> 0) AS elem) AS fe) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (SELECT CASE WHEN fe.elem IS NULL OR jsonb_typeof(fe.elem) = 'null' THEN NULL ELSE COALESCE(fe.elem->>'title', fe.elem->>'name', fe.elem #>> '{}') @@ -7775,9 +7752,8 @@ exports[`numeric functions > 'Odd' with 'autoNumber' 1`] = ` }, "result": "1", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."AutoNumber")::double precision AS val) AS v)", } `; @@ -7798,9 +7774,8 @@ exports[`numeric functions > 'Odd' with 'button' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -7821,9 +7796,8 @@ exports[`numeric functions > 'Odd' with 'checkbox' 1`] = ` }, "result": "1", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN "t"."Checkbox" IS NULL THEN NULL WHEN "t"."Checkbox" THEN 1 ELSE 0 END)::double precision AS val) AS v)", } `; @@ -7854,9 +7828,8 @@ exports[`numeric functions > 'Odd' with 'conditionalLookup' 1`] = ` }, "result": null, "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ((SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE (lkp.elem #>> '{}')::numeric @@ -7868,8 +7841,8 @@ exports[`numeric functions > 'Odd' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -7900,9 +7873,8 @@ exports[`numeric functions > 'Odd' with 'conditionalRollup' 1`] = ` }, "result": null, "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."ConditionalRollupType")::double precision AS val) AS v)", } `; @@ -7923,33 +7895,32 @@ exports[`numeric functions > 'Odd' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END) AS val) AS v) END))::text END", } `; @@ -7974,9 +7945,8 @@ exports[`numeric functions > 'Odd' with 'createdTime' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_datetime_to_number_odd", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_datetime_to_number_odd' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -8001,9 +7971,8 @@ exports[`numeric functions > 'Odd' with 'date' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_datetime_to_number_odd", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_datetime_to_number_odd' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -8027,9 +7996,8 @@ exports[`numeric functions > 'Odd' with 'formula' 1`] = ` }, "result": "11", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (10)::double precision AS val) AS v)", } `; @@ -8050,33 +8018,32 @@ exports[`numeric functions > 'Odd' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END) AS val) AS v) END))::text END", } `; @@ -8101,9 +8068,8 @@ exports[`numeric functions > 'Odd' with 'lastModifiedTime' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_datetime_to_number_odd", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_datetime_to_number_odd' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -8124,9 +8090,8 @@ exports[`numeric functions > 'Odd' with 'link' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN TRUE THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE ((CASE WHEN TRUE THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT NULL::double precision AS val) AS v) END))::text END", } `; @@ -8147,9 +8112,8 @@ exports[`numeric functions > 'Odd' with 'longText' 1`] = ` }, "result": "11", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."LongText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision @@ -8191,8 +8155,8 @@ exports[`numeric functions > 'Odd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8211,8 +8175,8 @@ exports[`numeric functions > 'Odd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8231,8 +8195,8 @@ exports[`numeric functions > 'Odd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8241,9 +8205,8 @@ exports[`numeric functions > 'Odd' with 'lookup' 1`] = ` END ELSE to_jsonb((("t"."LookupType"))) END) AS v) AS _lkp) -> 0) AS elem) AS lkp) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (SELECT CASE WHEN lkp.elem IS NULL OR jsonb_typeof(lkp.elem) = 'null' THEN NULL ELSE lkp.elem #>> '{}' @@ -8255,8 +8218,8 @@ exports[`numeric functions > 'Odd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8279,8 +8242,8 @@ exports[`numeric functions > 'Odd' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8320,9 +8283,8 @@ exports[`numeric functions > 'Odd' with 'multipleSelect' 1`] = ` ELSE fe.elem #>> '{}' END FROM (SELECT (COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb) -> 0) AS elem) AS fe) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (SELECT CASE WHEN fe.elem IS NULL OR jsonb_typeof(fe.elem) = 'null' THEN NULL ELSE fe.elem #>> '{}' @@ -8358,9 +8320,8 @@ exports[`numeric functions > 'Odd' with 'number' 1`] = ` }, "result": "11", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."Number")::double precision AS val) AS v)", } `; @@ -8381,9 +8342,8 @@ exports[`numeric functions > 'Odd' with 'rating' 1`] = ` }, "result": "5", "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."Rating")::double precision AS val) AS v)", } `; @@ -8407,9 +8367,8 @@ exports[`numeric functions > 'Odd' with 'rollup' 1`] = ` }, "result": null, "sql": "(SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT ("t"."RollupType")::double precision AS val) AS v)", } `; @@ -8430,9 +8389,8 @@ exports[`numeric functions > 'Odd' with 'singleLineText' 1`] = ` }, "result": "11", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleLineText" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision @@ -8457,9 +8415,8 @@ exports[`numeric functions > 'Odd' with 'singleSelect' 1`] = ` }, "result": "11", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleSelect" AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleSelect" AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleSelect" AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT "t"."SingleSelect" AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision @@ -8496,9 +8453,8 @@ exports[`numeric functions > 'Odd' with 'user' 1`] = ` ELSE COALESCE(fe.elem->>'title', fe.elem->>'name', fe.elem #>> '{}') END FROM (SELECT (COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb) -> 0) AS elem) AS fe) AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN MOD(((CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END))::numeric, 2::numeric) <> 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - WHEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) >= 0 THEN (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) + 1 - ELSE (CASE WHEN v.val > 0 THEN CEIL(v.val) ELSE FLOOR(v.val) END) - 1 + WHEN MOD((FLOOR(v.val))::numeric, 2::numeric) <> 0 THEN FLOOR(v.val) + ELSE (FLOOR(v.val) + 1) END) FROM (SELECT (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (SELECT CASE WHEN fe.elem IS NULL OR jsonb_typeof(fe.elem) = 'null' THEN NULL ELSE COALESCE(fe.elem->>'title', fe.elem->>'name', fe.elem #>> '{}') @@ -8655,8 +8611,8 @@ exports[`numeric functions > 'Power' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8706,33 +8662,33 @@ exports[`numeric functions > 'Power' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE POWER((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END), (2)::double precision) END))::text END", } `; @@ -8821,33 +8777,33 @@ exports[`numeric functions > 'Power' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE POWER((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END), (2)::double precision) END))::text END", } `; @@ -8950,8 +8906,8 @@ exports[`numeric functions > 'Power' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8970,8 +8926,8 @@ exports[`numeric functions > 'Power' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8990,8 +8946,8 @@ exports[`numeric functions > 'Power' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9010,8 +8966,8 @@ exports[`numeric functions > 'Power' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9030,8 +8986,8 @@ exports[`numeric functions > 'Power' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9054,8 +9010,8 @@ exports[`numeric functions > 'Power' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9285,35 +9241,35 @@ exports[`numeric functions > 'Round' with 'attachment' 1`] = ` }, }, "result": "[10.0, 20.0]", - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -9401,35 +9357,31 @@ exports[`numeric functions > 'Round' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN to_jsonb(CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN NULL ELSE ROUND((CASE + WHEN elem IS NULL OR jsonb_typeof(elem) = 'null' THEN NULL::double precision + WHEN __teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric') THEN (((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL - WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision - ELSE NULL - END) FROM (SELECT ((CASE - WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') - WHEN jsonb_typeof(elem) = 'array' THEN NULL - ELSE elem #>> '{}' - END))::text AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) + END))::text)::double precision + ELSE NULL::double precision + END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -9437,8 +9389,8 @@ exports[`numeric functions > 'Round' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -9489,33 +9441,33 @@ exports[`numeric functions > 'Round' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)::numeric, (1)::double precision::integer) END))::text END", } `; @@ -9604,33 +9556,33 @@ exports[`numeric functions > 'Round' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)::numeric, (1)::double precision::integer) END))::text END", } `; @@ -9722,35 +9674,35 @@ exports[`numeric functions > 'Round' with 'lookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -9758,8 +9710,8 @@ exports[`numeric functions > 'Round' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -9787,35 +9739,35 @@ exports[`numeric functions > 'Round' with 'multipleSelect' 1`] = ` }, }, "result": "[10.0, 20.0]", - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -9945,35 +9897,35 @@ exports[`numeric functions > 'Round' with 'user' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE ROUND((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END)::numeric, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -9994,35 +9946,35 @@ exports[`numeric functions > 'RoundDown' with 'attachment' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -10110,35 +10062,31 @@ exports[`numeric functions > 'RoundDown' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN to_jsonb(CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN NULL ELSE FLOOR((CASE + WHEN elem IS NULL OR jsonb_typeof(elem) = 'null' THEN NULL::double precision + WHEN __teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric') THEN (((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL - WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision - ELSE NULL - END) FROM (SELECT ((CASE - WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') - WHEN jsonb_typeof(elem) = 'array' THEN NULL - ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END))::text)::double precision + ELSE NULL::double precision + END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -10146,8 +10094,8 @@ exports[`numeric functions > 'RoundDown' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -10198,33 +10146,33 @@ exports[`numeric functions > 'RoundDown' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END))::text END", } `; @@ -10313,33 +10261,33 @@ exports[`numeric functions > 'RoundDown' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END))::text END", } `; @@ -10431,35 +10379,35 @@ exports[`numeric functions > 'RoundDown' with 'lookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -10467,8 +10415,8 @@ exports[`numeric functions > 'RoundDown' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -10496,35 +10444,35 @@ exports[`numeric functions > 'RoundDown' with 'multipleSelect' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -10654,35 +10602,35 @@ exports[`numeric functions > 'RoundDown' with 'user' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE FLOOR((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -10745,35 +10693,35 @@ exports[`numeric functions > 'RoundUp' with 'attachment' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -10861,35 +10809,31 @@ exports[`numeric functions > 'RoundUp' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN to_jsonb(CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN NULL ELSE CEIL((CASE + WHEN elem IS NULL OR jsonb_typeof(elem) = 'null' THEN NULL::double precision + WHEN __teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric') THEN (((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL - WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision - ELSE NULL - END) FROM (SELECT ((CASE - WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') - WHEN jsonb_typeof(elem) = 'array' THEN NULL - ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END))::text)::double precision + ELSE NULL::double precision + END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -10897,8 +10841,8 @@ exports[`numeric functions > 'RoundUp' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -10949,33 +10893,33 @@ exports[`numeric functions > 'RoundUp' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END))::text END", } `; @@ -11064,33 +11008,33 @@ exports[`numeric functions > 'RoundUp' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END))::text END", } `; @@ -11182,35 +11126,35 @@ exports[`numeric functions > 'RoundUp' with 'lookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -11218,8 +11162,8 @@ exports[`numeric functions > 'RoundUp' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11247,35 +11191,35 @@ exports[`numeric functions > 'RoundUp' with 'multipleSelect' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -11405,35 +11349,35 @@ exports[`numeric functions > 'RoundUp' with 'user' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN to_jsonb(CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END) ELSE to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE CEIL((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) + END) AS val) AS v) END) * POWER(10, (1)::double precision::integer)) / POWER(10, (1)::double precision::integer) END)) END ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -11596,8 +11540,8 @@ exports[`numeric functions > 'Sqrt' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -11647,29 +11591,29 @@ exports[`numeric functions > 'Sqrt' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE SQRT((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -11758,29 +11702,29 @@ exports[`numeric functions > 'Sqrt' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE SQRT((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END)) END))::text END", } `; @@ -11883,8 +11827,8 @@ exports[`numeric functions > 'Sqrt' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11903,8 +11847,8 @@ exports[`numeric functions > 'Sqrt' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11923,8 +11867,8 @@ exports[`numeric functions > 'Sqrt' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11943,8 +11887,8 @@ exports[`numeric functions > 'Sqrt' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -11967,8 +11911,8 @@ exports[`numeric functions > 'Sqrt' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12310,8 +12254,8 @@ exports[`numeric functions > 'Sum' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -12362,33 +12306,33 @@ exports[`numeric functions > 'Sum' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END) + (2)::double precision) END))::text END", } `; @@ -12477,33 +12421,33 @@ exports[`numeric functions > 'Sum' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END) + (2)::double precision) END))::text END", } `; @@ -12615,8 +12559,8 @@ exports[`numeric functions > 'Sum' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -12883,23 +12827,23 @@ exports[`numeric functions > 'Value' with 'attachment' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) END)) ORDER BY ord) + END) AS val) AS v) END) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."Attachment")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -12987,23 +12931,23 @@ exports[`numeric functions > 'Value' with 'conditionalLookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (elem IS NOT NULL AND jsonb_typeof(elem) <> 'null' AND NOT (__teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END))::text, 'numeric'))) THEN NULL ELSE (CASE + WHEN elem IS NULL OR jsonb_typeof(elem) = 'null' THEN NULL::double precision + WHEN __teable_input_is_valid(((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE - WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL - WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision - ELSE NULL - END) FROM (SELECT ((CASE + END))::text, 'numeric') THEN (((CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) END)) ORDER BY ord) + END))::text)::double precision + ELSE NULL::double precision + END) END)) ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -13011,8 +12955,8 @@ exports[`numeric functions > 'Value' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -13063,25 +13007,25 @@ exports[`numeric functions > 'Value' with 'createdBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) AS val) AS v) END))::text END", } `; @@ -13170,25 +13114,25 @@ exports[`numeric functions > 'Value' with 'lastModifiedBy' 1`] = ` }, "result": "#ERROR:TYPE:cannot_cast_to_number", "sql": "CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN '#ERROR:TYPE:cannot_cast_to_number' ELSE '#ERROR:TYPE:cannot_cast_to_number' END ELSE ((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL END) FROM (SELECT (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) AS val) AS v) END))::text END", } `; @@ -13280,23 +13224,23 @@ exports[`numeric functions > 'Value' with 'lookup' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) END)) ORDER BY ord) + END) AS val) AS v) END) END)) ORDER BY ord) FROM jsonb_array_elements((SELECT CASE WHEN _lkp.v IS NULL THEN '[]'::jsonb WHEN jsonb_typeof(_lkp.v) = 'null' THEN '[]'::jsonb @@ -13304,8 +13248,8 @@ exports[`numeric functions > 'Value' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -13333,23 +13277,23 @@ exports[`numeric functions > 'Value' with 'multipleSelect' 1`] = ` }, }, "result": "[10, 20]", - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) END)) ORDER BY ord) + END) AS val) AS v) END) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."MultipleSelect")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } @@ -13479,23 +13423,23 @@ exports[`numeric functions > 'Value' with 'user' 1`] = ` }, }, "result": null, - "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + "sql": "(SELECT jsonb_agg(to_jsonb((CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT ((CASE + END) AS val) AS v) THEN NULL ELSE (CASE WHEN (SELECT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NOT (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric'))) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) THEN NULL ELSE (SELECT (CASE + END) AS val) AS v) THEN NULL ELSE (SELECT (CASE WHEN NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NULL THEN NULL WHEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)') IS NOT NULL AND NOT (NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') IS NOT NULL AND NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') ~ '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)[eE][+-]?\\d+') AND __teable_input_is_valid(SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'), 'numeric')) THEN (SUBSTRING(NULLIF(REGEXP_REPLACE(BTRIM((v.val)::text), '[,\\s]', '', 'g'), '') FROM '^([+-]?\\d+\\.?\\d*|[+-]?\\d*\\.\\d+)'))::double precision ELSE NULL - END) FROM (SELECT ((CASE + END) FROM (SELECT (CASE WHEN jsonb_typeof(elem) = 'object' THEN COALESCE(elem->>'title', elem->>'name', elem #>> '{}') WHEN jsonb_typeof(elem) = 'array' THEN NULL ELSE elem #>> '{}' - END))::text AS val) AS v) END) END)) ORDER BY ord) + END) AS val) AS v) END) END)) ORDER BY ord) FROM jsonb_array_elements(COALESCE(NULLIF(("t"."User")::jsonb, 'null'::jsonb), '[]'::jsonb)) WITH ORDINALITY AS _jae(elem, ord) )", } diff --git a/packages/v2/formula-sql-pg/src/__snapshots__/TextFunctions.spec.ts.snap b/packages/v2/formula-sql-pg/src/__snapshots__/TextFunctions.spec.ts.snap index 4d1cb71b2..093449fea 100644 --- a/packages/v2/formula-sql-pg/src/__snapshots__/TextFunctions.spec.ts.snap +++ b/packages/v2/formula-sql-pg/src/__snapshots__/TextFunctions.spec.ts.snap @@ -113,8 +113,8 @@ exports[`text functions > 'Concatenate' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -165,9 +165,9 @@ exports[`text functions > 'Concatenate' with 'createdBy' 1`] = ` }, "result": "System-x", "sql": "CONCAT((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '-x')", } `; @@ -256,9 +256,9 @@ exports[`text functions > 'Concatenate' with 'lastModifiedBy' 1`] = ` }, "result": "System-x", "sql": "CONCAT((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '-x')", } `; @@ -355,8 +355,8 @@ exports[`text functions > 'Concatenate' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -694,8 +694,8 @@ exports[`text functions > 'EncodeUrlComponent' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -727,8 +727,8 @@ exports[`text functions > 'EncodeUrlComponent' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -797,9 +797,9 @@ exports[`text functions > 'EncodeUrlComponent' with 'createdBy' 1`] = ` }, "result": "System", "sql": "(CASE WHEN (CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) IS NULL THEN NULL ELSE COALESCE((SELECT string_agg( CASE WHEN byte_val BETWEEN 48 AND 57 @@ -815,9 +815,9 @@ exports[`text functions > 'EncodeUrlComponent' with 'createdBy' 1`] = ` FROM ( SELECT ord, get_byte(src.bytes, ord) AS byte_val FROM (SELECT convert_to(((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))::text, 'UTF8') AS bytes) AS src CROSS JOIN generate_series(0, octet_length(src.bytes) - 1) AS ord ) AS utf8_bytes), '') END)", @@ -956,9 +956,9 @@ exports[`text functions > 'EncodeUrlComponent' with 'lastModifiedBy' 1`] = ` }, "result": "System", "sql": "(CASE WHEN (CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) IS NULL THEN NULL ELSE COALESCE((SELECT string_agg( CASE WHEN byte_val BETWEEN 48 AND 57 @@ -974,9 +974,9 @@ exports[`text functions > 'EncodeUrlComponent' with 'lastModifiedBy' 1`] = ` FROM ( SELECT ord, get_byte(src.bytes, ord) AS byte_val FROM (SELECT convert_to(((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))::text, 'UTF8') AS bytes) AS src CROSS JOIN generate_series(0, octet_length(src.bytes) - 1) AS ord ) AS utf8_bytes), '') END)", @@ -1123,8 +1123,8 @@ exports[`text functions > 'EncodeUrlComponent' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1156,8 +1156,8 @@ exports[`text functions > 'EncodeUrlComponent' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -1548,8 +1548,8 @@ exports[`text functions > 'Find' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -1600,9 +1600,9 @@ exports[`text functions > 'Find' with 'createdBy' 1`] = ` }, "result": "0", "sql": "POSITION('1' IN SUBSTRING((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) FROM (1)::double precision::integer)) + (1)::double precision::integer - 1", } `; @@ -1691,9 +1691,9 @@ exports[`text functions > 'Find' with 'lastModifiedBy' 1`] = ` }, "result": "0", "sql": "POSITION('1' IN SUBSTRING((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) FROM (1)::double precision::integer)) + (1)::double precision::integer - 1", } `; @@ -1790,8 +1790,8 @@ exports[`text functions > 'Find' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2080,8 +2080,8 @@ exports[`text functions > 'Left' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2132,9 +2132,9 @@ exports[`text functions > 'Left' with 'createdBy' 1`] = ` }, "result": "S", "sql": "LEFT((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), (1)::double precision::integer)", } `; @@ -2223,9 +2223,9 @@ exports[`text functions > 'Left' with 'lastModifiedBy' 1`] = ` }, "result": "S", "sql": "LEFT((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), (1)::double precision::integer)", } `; @@ -2322,8 +2322,8 @@ exports[`text functions > 'Left' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -2594,8 +2594,8 @@ exports[`text functions > 'Len' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -2646,9 +2646,9 @@ exports[`text functions > 'Len' with 'createdBy' 1`] = ` }, "result": "6", "sql": "LENGTH((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))", } `; @@ -2737,9 +2737,9 @@ exports[`text functions > 'Len' with 'lastModifiedBy' 1`] = ` }, "result": "6", "sql": "LENGTH((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))", } `; @@ -2836,8 +2836,8 @@ exports[`text functions > 'Len' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3108,8 +3108,8 @@ exports[`text functions > 'Lower' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3160,9 +3160,9 @@ exports[`text functions > 'Lower' with 'createdBy' 1`] = ` }, "result": "system", "sql": "LOWER((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))", } `; @@ -3251,9 +3251,9 @@ exports[`text functions > 'Lower' with 'lastModifiedBy' 1`] = ` }, "result": "system", "sql": "LOWER((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))", } `; @@ -3350,8 +3350,8 @@ exports[`text functions > 'Lower' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -3622,8 +3622,8 @@ exports[`text functions > 'Mid' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -3674,9 +3674,9 @@ exports[`text functions > 'Mid' with 'createdBy' 1`] = ` }, "result": "Sy", "sql": "SUBSTRING((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) FROM (1)::double precision::integer FOR (2)::double precision::integer)", } `; @@ -3765,9 +3765,9 @@ exports[`text functions > 'Mid' with 'lastModifiedBy' 1`] = ` }, "result": "Sy", "sql": "SUBSTRING((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) FROM (1)::double precision::integer FOR (2)::double precision::integer)", } `; @@ -3864,8 +3864,8 @@ exports[`text functions > 'Mid' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4136,8 +4136,8 @@ exports[`text functions > 'RegExpReplace' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -4188,9 +4188,9 @@ exports[`text functions > 'RegExpReplace' with 'createdBy' 1`] = ` }, "result": "System", "sql": "REGEXP_REPLACE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '1', 'x', 'g')", } `; @@ -4279,9 +4279,9 @@ exports[`text functions > 'RegExpReplace' with 'lastModifiedBy' 1`] = ` }, "result": "System", "sql": "REGEXP_REPLACE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '1', 'x', 'g')", } `; @@ -4378,8 +4378,8 @@ exports[`text functions > 'RegExpReplace' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -4650,8 +4650,8 @@ exports[`text functions > 'Replace' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -4702,9 +4702,9 @@ exports[`text functions > 'Replace' with 'createdBy' 1`] = ` }, "result": "xystem", "sql": "OVERLAY((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) PLACING 'x' FROM (1)::double precision::integer FOR (1)::double precision::integer)", } `; @@ -4793,9 +4793,9 @@ exports[`text functions > 'Replace' with 'lastModifiedBy' 1`] = ` }, "result": "xystem", "sql": "OVERLAY((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) PLACING 'x' FROM (1)::double precision::integer FOR (1)::double precision::integer)", } `; @@ -4892,8 +4892,8 @@ exports[`text functions > 'Replace' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -5164,8 +5164,8 @@ exports[`text functions > 'Rept' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -5216,9 +5216,9 @@ exports[`text functions > 'Rept' with 'createdBy' 1`] = ` }, "result": "SystemSystem", "sql": "REPEAT((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), (2)::double precision::integer)", } `; @@ -5307,9 +5307,9 @@ exports[`text functions > 'Rept' with 'lastModifiedBy' 1`] = ` }, "result": "SystemSystem", "sql": "REPEAT((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), (2)::double precision::integer)", } `; @@ -5406,8 +5406,8 @@ exports[`text functions > 'Rept' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -5678,8 +5678,8 @@ exports[`text functions > 'Right' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -5730,9 +5730,9 @@ exports[`text functions > 'Right' with 'createdBy' 1`] = ` }, "result": "m", "sql": "RIGHT((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), (1)::double precision::integer)", } `; @@ -5821,9 +5821,9 @@ exports[`text functions > 'Right' with 'lastModifiedBy' 1`] = ` }, "result": "m", "sql": "RIGHT((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), (1)::double precision::integer)", } `; @@ -5920,8 +5920,8 @@ exports[`text functions > 'Right' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6192,8 +6192,8 @@ exports[`text functions > 'Search' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6244,9 +6244,9 @@ exports[`text functions > 'Search' with 'createdBy' 1`] = ` }, "result": "0", "sql": "POSITION(UPPER('1') IN UPPER(SUBSTRING((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END) FROM (1)::double precision::integer))) + (1)::double precision::integer - 1", } `; @@ -6335,9 +6335,9 @@ exports[`text functions > 'Search' with 'lastModifiedBy' 1`] = ` }, "result": "0", "sql": "POSITION(UPPER('1') IN UPPER(SUBSTRING((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END) FROM (1)::double precision::integer))) + (1)::double precision::integer - 1", } `; @@ -6434,8 +6434,8 @@ exports[`text functions > 'Search' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -6724,8 +6724,8 @@ exports[`text functions > 'Substitute' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -6756,7 +6756,7 @@ exports[`text functions > 'Substitute' with 'conditionalRollup' 1`] = ` }, }, "result": null, - "sql": "REPLACE(trim(to_char(("t"."ConditionalRollupType")::numeric, '999999990D00')), '1', 'x')", + "sql": "REPLACE(("t"."ConditionalRollupType")::text, '1', 'x')", } `; @@ -6776,9 +6776,9 @@ exports[`text functions > 'Substitute' with 'createdBy' 1`] = ` }, "result": "System", "sql": "REPLACE((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END), '1', 'x')", } `; @@ -6801,8 +6801,8 @@ exports[`text functions > 'Substitute' with 'createdTime' 1`] = ` "rawValue": "0000-00-00 00:00:00.000+00", }, }, - "result": "0000/0x/00 00:00", - "sql": "REPLACE(TO_CHAR(("t"."CreatedTime")::timestamptz AT TIME ZONE 'UTC', 'YYYY/MM/DD HH24:MI'), '1', 'x')", + "result": "0000-0x-00 00:00:00.000+00", + "sql": "REPLACE(("t"."CreatedTime")::text, '1', 'x')", } `; @@ -6824,8 +6824,8 @@ exports[`text functions > 'Substitute' with 'date' 1`] = ` "rawValue": "2024-02-03 00:00:00+00", }, }, - "result": "2024/02/03 00:00", - "sql": "REPLACE(TO_CHAR(("t"."Date")::timestamptz AT TIME ZONE 'UTC', 'YYYY/MM/DD HH24:MI'), '1', 'x')", + "result": "2024-02-03 00:00:00+00", + "sql": "REPLACE(("t"."Date")::text, '1', 'x')", } `; @@ -6846,8 +6846,8 @@ exports[`text functions > 'Substitute' with 'formula' 1`] = ` "rawValue": null, }, }, - "result": "x0.00", - "sql": "REPLACE(trim(to_char((10)::numeric, '999999990D00')), '1', 'x')", + "result": "x0", + "sql": "REPLACE((10)::text, '1', 'x')", } `; @@ -6867,9 +6867,9 @@ exports[`text functions > 'Substitute' with 'lastModifiedBy' 1`] = ` }, "result": "System", "sql": "REPLACE((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END), '1', 'x')", } `; @@ -6892,8 +6892,8 @@ exports[`text functions > 'Substitute' with 'lastModifiedTime' 1`] = ` "rawValue": "0000-00-00 00:00:00.000+00", }, }, - "result": "0000/0x/00 00:00", - "sql": "REPLACE(TO_CHAR(("t"."LastModifiedTime")::timestamptz AT TIME ZONE 'UTC', 'YYYY/MM/DD HH24:MI'), '1', 'x')", + "result": "0000-0x-00 00:00:00.000+00", + "sql": "REPLACE(("t"."LastModifiedTime")::text, '1', 'x')", } `; @@ -6966,8 +6966,8 @@ exports[`text functions > 'Substitute' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7019,8 +7019,8 @@ exports[`text functions > 'Substitute' with 'number' 1`] = ` "rawValue": "10", }, }, - "result": "x0.00", - "sql": "REPLACE(trim(to_char(("t"."Number")::numeric, '999999990D00')), '1', 'x')", + "result": "x0", + "sql": "REPLACE(("t"."Number")::text, '1', 'x')", } `; @@ -7061,7 +7061,7 @@ exports[`text functions > 'Substitute' with 'rollup' 1`] = ` }, }, "result": null, - "sql": "REPLACE(trim(to_char(("t"."RollupType")::numeric, '999999990D00')), '1', 'x')", + "sql": "REPLACE(("t"."RollupType")::text, '1', 'x')", } `; @@ -7161,8 +7161,8 @@ exports[`text functions > 'T' with 'autoNumber' 1`] = ` "rawValue": "1", }, }, - "result": null, - "sql": "NULL", + "result": "1", + "sql": "("t"."AutoNumber")::text", } `; @@ -7199,8 +7199,8 @@ exports[`text functions > 'T' with 'checkbox' 1`] = ` "rawValue": "true", }, }, - "result": null, - "sql": "NULL", + "result": "true", + "sql": "("t"."Checkbox")::text", } `; @@ -7238,8 +7238,8 @@ exports[`text functions > 'T' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -7270,7 +7270,7 @@ exports[`text functions > 'T' with 'conditionalRollup' 1`] = ` }, }, "result": null, - "sql": "NULL", + "sql": "("t"."ConditionalRollupType")::text", } `; @@ -7288,8 +7288,12 @@ exports[`text functions > 'T' with 'createdBy' 1`] = ` "rawValue": "{"id": "system", "email": null, "title": "System", "avatarUrl": "/api/attachments/read/public/avatar/system"}", }, }, - "result": "{"id": "system", "email": null, "title": "System", "avatarUrl": "/api/attachments/read/public/avatar/system"}", - "sql": ""t"."CreatedBy"", + "result": "System", + "sql": "(CASE + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' + END)", } `; @@ -7311,8 +7315,8 @@ exports[`text functions > 'T' with 'createdTime' 1`] = ` "rawValue": "0000-00-00 00:00:00.000+00", }, }, - "result": null, - "sql": "NULL", + "result": "0000-00-00 00:00:00.000+00", + "sql": "("t"."CreatedTime")::text", } `; @@ -7334,8 +7338,8 @@ exports[`text functions > 'T' with 'date' 1`] = ` "rawValue": "2024-02-03 00:00:00+00", }, }, - "result": null, - "sql": "NULL", + "result": "2024-02-03 00:00:00+00", + "sql": "("t"."Date")::text", } `; @@ -7356,8 +7360,8 @@ exports[`text functions > 'T' with 'formula' 1`] = ` "rawValue": null, }, }, - "result": null, - "sql": "NULL", + "result": "10", + "sql": "(10)::text", } `; @@ -7375,8 +7379,12 @@ exports[`text functions > 'T' with 'lastModifiedBy' 1`] = ` "rawValue": "{"id": "system", "email": null, "title": "System", "avatarUrl": "/api/attachments/read/public/avatar/system"}", }, }, - "result": "{"id": "system", "email": null, "title": "System", "avatarUrl": "/api/attachments/read/public/avatar/system"}", - "sql": ""t"."LastModifiedBy"", + "result": "System", + "sql": "(CASE + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' + END)", } `; @@ -7398,8 +7406,8 @@ exports[`text functions > 'T' with 'lastModifiedTime' 1`] = ` "rawValue": "0000-00-00 00:00:00.000+00", }, }, - "result": null, - "sql": "NULL", + "result": "0000-00-00 00:00:00.000+00", + "sql": "("t"."LastModifiedTime")::text", } `; @@ -7472,8 +7480,8 @@ exports[`text functions > 'T' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -7525,8 +7533,8 @@ exports[`text functions > 'T' with 'number' 1`] = ` "rawValue": "10", }, }, - "result": null, - "sql": "NULL", + "result": "10", + "sql": "("t"."Number")::text", } `; @@ -7544,8 +7552,8 @@ exports[`text functions > 'T' with 'rating' 1`] = ` "rawValue": "4", }, }, - "result": null, - "sql": "NULL", + "result": "4", + "sql": "("t"."Rating")::text", } `; @@ -7567,7 +7575,7 @@ exports[`text functions > 'T' with 'rollup' 1`] = ` }, }, "result": null, - "sql": "NULL", + "sql": "("t"."RollupType")::text", } `; @@ -7744,8 +7752,8 @@ exports[`text functions > 'Trim' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -7796,9 +7804,9 @@ exports[`text functions > 'Trim' with 'createdBy' 1`] = ` }, "result": "System", "sql": "TRIM((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))", } `; @@ -7887,9 +7895,9 @@ exports[`text functions > 'Trim' with 'lastModifiedBy' 1`] = ` }, "result": "System", "sql": "TRIM((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))", } `; @@ -7986,8 +7994,8 @@ exports[`text functions > 'Trim' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL @@ -8258,8 +8266,8 @@ exports[`text functions > 'Upper' with 'conditionalLookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."ConditionalLookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb - WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN ((("t"."ConditionalLookupType")))::jsonb + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) + WHEN pg_typeof((("t"."ConditionalLookupType"))) = 'json'::regtype THEN to_jsonb((("t"."ConditionalLookupType"))) WHEN pg_typeof((("t"."ConditionalLookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."ConditionalLookupType")))::text), '') IS NULL THEN NULL @@ -8310,9 +8318,9 @@ exports[`text functions > 'Upper' with 'createdBy' 1`] = ` }, "result": "SYSTEM", "sql": "UPPER((CASE - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'object' THEN COALESCE(("t"."CreatedBy")::jsonb->>'title', ("t"."CreatedBy")::jsonb->>'name', ("t"."CreatedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."CreatedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."CreatedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'object' THEN COALESCE(to_jsonb("t"."CreatedBy")->>'title', to_jsonb("t"."CreatedBy")->>'name', to_jsonb("t"."CreatedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."CreatedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."CreatedBy") #>> '{}' END))", } `; @@ -8401,9 +8409,9 @@ exports[`text functions > 'Upper' with 'lastModifiedBy' 1`] = ` }, "result": "SYSTEM", "sql": "UPPER((CASE - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'object' THEN COALESCE(("t"."LastModifiedBy")::jsonb->>'title', ("t"."LastModifiedBy")::jsonb->>'name', ("t"."LastModifiedBy")::jsonb #>> '{}') - WHEN jsonb_typeof(("t"."LastModifiedBy")::jsonb) = 'array' THEN NULL - ELSE ("t"."LastModifiedBy")::jsonb #>> '{}' + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'object' THEN COALESCE(to_jsonb("t"."LastModifiedBy")->>'title', to_jsonb("t"."LastModifiedBy")->>'name', to_jsonb("t"."LastModifiedBy") #>> '{}') + WHEN jsonb_typeof(to_jsonb("t"."LastModifiedBy")) = 'array' THEN NULL + ELSE to_jsonb("t"."LastModifiedBy") #>> '{}' END))", } `; @@ -8500,8 +8508,8 @@ exports[`text functions > 'Upper' with 'lookup' 1`] = ` ELSE jsonb_build_array(_lkp.v) END FROM (SELECT (CASE WHEN (("t"."LookupType")) IS NULL THEN NULL - WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN ((("t"."LookupType")))::jsonb - WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN ((("t"."LookupType")))::jsonb + WHEN pg_typeof((("t"."LookupType"))) = 'jsonb'::regtype THEN to_jsonb((("t"."LookupType"))) + WHEN pg_typeof((("t"."LookupType"))) = 'json'::regtype THEN to_jsonb((("t"."LookupType"))) WHEN pg_typeof((("t"."LookupType"))) IN ('text', 'varchar', 'bpchar', 'character varying', 'unknown') THEN CASE WHEN NULLIF(BTRIM(((("t"."LookupType")))::text), '') IS NULL THEN NULL diff --git a/packages/v2/test-node/src/commands/CreateFieldHandler.db.spec.ts b/packages/v2/test-node/src/commands/CreateFieldHandler.db.spec.ts index 04956384f..0d75ab36b 100644 --- a/packages/v2/test-node/src/commands/CreateFieldHandler.db.spec.ts +++ b/packages/v2/test-node/src/commands/CreateFieldHandler.db.spec.ts @@ -10,6 +10,7 @@ import { type CreateTableResult, FieldId, type ICommandBus, + type ITableRepository, v2CoreTokens, } from '@teable/v2-core'; import type { V1TeableDatabase } from '@teable/v2-postgres-schema'; @@ -298,7 +299,7 @@ describe('CreateFieldHandler (db)', () => { expect(checkboxRow.is_multiple_cell_value).toBe(false); expect(checkboxRow.db_field_type).toBe('BOOLEAN'); expect(checkboxRow.not_null).toBeNull(); - expect(checkboxRow.unique).toBeNull(); + expect(checkboxRow.unique).toBe(false); expect(checkboxRow.is_computed).toBeNull(); expect(JSON.parse(checkboxRow.options ?? '')).toEqual({ defaultValue: true }); @@ -326,7 +327,7 @@ describe('CreateFieldHandler (db)', () => { expect(formulaRow.is_multiple_cell_value).toBe(false); expect(formulaRow.db_field_type).toBe('REAL'); expect(formulaRow.not_null).toBeNull(); - expect(formulaRow.unique).toBeNull(); + expect(formulaRow.unique).toBe(false); expect(formulaRow.is_computed).toBe(true); expect(JSON.parse(formulaRow.options ?? '')).toEqual({ expression: `{${numberFieldId}} * 2`, @@ -498,6 +499,83 @@ describe('CreateFieldHandler (db)', () => { expect(updatedViewMetaDb).toEqual(updatedViewMeta); }); + it('persists and rehydrates aiConfig on field create', async () => { + const { container, baseId } = getV2NodeTestContainer(); + const commandBus = container.resolve(v2CoreTokens.commandBus); + const tableRepository = container.resolve(v2CoreTokens.tableRepository); + const db = container.resolve>(v2PostgresDbTokens.db); + + const actorIdResult = ActorId.create('system'); + actorIdResult._unsafeUnwrap(); + const context = { actorId: actorIdResult._unsafeUnwrap() }; + + const createTableResult = CreateTableCommand.create({ + baseId: baseId.toString(), + name: 'AI Config Table', + fields: [{ type: 'singleLineText', name: 'Title' }], + }); + createTableResult._unsafeUnwrap(); + + const createdTableResult = await commandBus.execute( + context, + createTableResult._unsafeUnwrap() + ); + createdTableResult._unsafeUnwrap(); + const createdTable = createdTableResult._unsafeUnwrap().table; + + const aiFieldId = FieldId.mustGenerate().toString(); + const aiConfig = { + type: 'summary', + modelKey: 'openai@gpt-4o@gpt', + sourceFieldId: createdTable.primaryFieldId().toString(), + }; + + const createFieldResult = CreateFieldCommand.create({ + baseId: baseId.toString(), + tableId: createdTable.id().toString(), + field: { + id: aiFieldId, + type: 'singleLineText', + name: 'AI Summary', + aiConfig, + }, + }); + createFieldResult._unsafeUnwrap(); + + const createdFieldResult = await commandBus.execute( + context, + createFieldResult._unsafeUnwrap() + ); + createdFieldResult._unsafeUnwrap(); + + const persistedRow = await db + .selectFrom('field') + .select(['id', 'ai_config']) + .where('id', '=', aiFieldId) + .executeTakeFirst(); + + expect(persistedRow).toBeTruthy(); + if (!persistedRow) return; + expect(persistedRow.id).toBe(aiFieldId); + expect(JSON.parse(persistedRow.ai_config ?? 'null')).toEqual(aiConfig); + + const byIdSpecResult = createdTable.specs().byId(createdTable.id()).build(); + byIdSpecResult._unsafeUnwrap(); + + const reloadedTableResult = await tableRepository.findOne( + context, + byIdSpecResult._unsafeUnwrap() + ); + reloadedTableResult._unsafeUnwrap(); + const reloadedTable = reloadedTableResult._unsafeUnwrap(); + + const reloadedField = reloadedTable + .getFields() + .find((field) => field.id().toString() === aiFieldId); + expect(reloadedField).toBeTruthy(); + expect(reloadedField?.aiConfig()).toEqual(aiConfig); + }); + it('persists all field types and link side effects', async () => { const { container, baseId } = getV2NodeTestContainer(); const commandBus = container.resolve(v2CoreTokens.commandBus); @@ -940,4 +1018,209 @@ describe('CreateFieldHandler (db)', () => { { from_field_id: hostTable.primaryFieldId().toString(), to_field_id: symmetricLinkId }, ]); }); + + it('uses provided link db config when creating link fields', async () => { + const { container, baseId } = getV2NodeTestContainer(); + const commandBus = container.resolve(v2CoreTokens.commandBus); + const db = container.resolve>(v2PostgresDbTokens.db); + + const actorIdResult = ActorId.create('system'); + actorIdResult._unsafeUnwrap(); + const context = { actorId: actorIdResult._unsafeUnwrap() }; + + const createHostResult = CreateTableCommand.create({ + baseId: baseId.toString(), + name: 'Configured Link Host', + fields: [{ type: 'singleLineText', name: 'Name' }], + }); + createHostResult._unsafeUnwrap(); + const hostExec = await commandBus.execute( + context, + createHostResult._unsafeUnwrap() + ); + hostExec._unsafeUnwrap(); + const hostTable = hostExec._unsafeUnwrap().table; + const hostTableId = hostTable.id().toString(); + + const createForeignResult = CreateTableCommand.create({ + baseId: baseId.toString(), + name: 'Configured Link Foreign', + fields: [{ type: 'singleLineText', name: 'Title' }], + }); + createForeignResult._unsafeUnwrap(); + const foreignExec = await commandBus.execute( + context, + createForeignResult._unsafeUnwrap() + ); + foreignExec._unsafeUnwrap(); + const foreignTable = foreignExec._unsafeUnwrap().table; + const foreignTableId = foreignTable.id().toString(); + const foreignPrimaryFieldId = foreignTable.primaryFieldId().toString(); + + const linkId = `fld${'p'.repeat(16)}`; + const symmetricLinkId = `fld${'q'.repeat(16)}`; + const customJunctionTable = `junction_cfg_${linkId.slice(-4)}_${symmetricLinkId.slice(-4)}`; + const customFkHostTableName = `${baseId.toString()}.${customJunctionTable}`; + const selfKeyName = `__fk_${symmetricLinkId}`; + const foreignKeyName = `__fk_${linkId}`; + + const commandResult = CreateFieldCommand.create({ + baseId: baseId.toString(), + tableId: hostTableId, + field: { + type: 'link', + id: linkId, + name: 'Configured ManyMany Link', + options: { + relationship: 'manyMany', + foreignTableId, + lookupFieldId: foreignPrimaryFieldId, + symmetricFieldId: symmetricLinkId, + fkHostTableName: customFkHostTableName, + selfKeyName, + foreignKeyName, + }, + }, + }); + commandResult._unsafeUnwrap(); + + const execResult = await commandBus.execute( + context, + commandResult._unsafeUnwrap() + ); + execResult._unsafeUnwrap(); + + const createdLinkRow = await db + .selectFrom('field') + .select(['id', 'options', 'table_id']) + .where('id', '=', linkId) + .executeTakeFirst(); + expect(createdLinkRow).toBeTruthy(); + if (!createdLinkRow) return; + expect(createdLinkRow.table_id).toBe(hostTableId); + + const createdOptions = JSON.parse(createdLinkRow.options ?? '{}') as Record; + expect(createdOptions.fkHostTableName).toBe(customFkHostTableName); + expect(createdOptions.selfKeyName).toBe(selfKeyName); + expect(createdOptions.foreignKeyName).toBe(foreignKeyName); + + const symmetricRow = await db + .selectFrom('field') + .select(['id', 'options', 'table_id']) + .where('id', '=', symmetricLinkId) + .executeTakeFirst(); + expect(symmetricRow).toBeTruthy(); + if (!symmetricRow) return; + expect(symmetricRow.table_id).toBe(foreignTableId); + + const symmetricOptions = JSON.parse(symmetricRow.options ?? '{}') as Record; + expect(symmetricOptions.fkHostTableName).toBe(customFkHostTableName); + expect(symmetricOptions.selfKeyName).toBe(foreignKeyName); + expect(symmetricOptions.foreignKeyName).toBe(selfKeyName); + + const customJunctionRows = await db + .withSchema('information_schema') + .selectFrom('tables') + .select(['table_name']) + .where('table_schema', '=', baseId.toString()) + .where('table_name', '=', customJunctionTable) + .execute(); + expect(customJunctionRows).toHaveLength(1); + + const defaultJunctionTable = `junction_${linkId}_${symmetricLinkId}`; + const defaultJunctionRows = await db + .withSchema('information_schema') + .selectFrom('tables') + .select(['table_name']) + .where('table_schema', '=', baseId.toString()) + .where('table_name', '=', defaultJunctionTable) + .execute(); + expect(defaultJunctionRows).toHaveLength(0); + }); + + it('defaults link lookupFieldId to foreign primary field when omitted', async () => { + const { container, baseId } = getV2NodeTestContainer(); + const commandBus = container.resolve(v2CoreTokens.commandBus); + const db = container.resolve>(v2PostgresDbTokens.db); + + const actorIdResult = ActorId.create('system'); + actorIdResult._unsafeUnwrap(); + const context = { actorId: actorIdResult._unsafeUnwrap() }; + + const createHostResult = CreateTableCommand.create({ + baseId: baseId.toString(), + name: 'Link Host Without Lookup', + fields: [{ type: 'singleLineText', name: 'Name' }], + }); + createHostResult._unsafeUnwrap(); + const hostExec = await commandBus.execute( + context, + createHostResult._unsafeUnwrap() + ); + hostExec._unsafeUnwrap(); + const hostTable = hostExec._unsafeUnwrap().table; + const hostTableId = hostTable.id().toString(); + const hostPrimaryFieldId = hostTable.primaryFieldId().toString(); + + const createForeignResult = CreateTableCommand.create({ + baseId: baseId.toString(), + name: 'Link Foreign Without Lookup', + fields: [{ type: 'singleLineText', name: 'Title' }], + }); + createForeignResult._unsafeUnwrap(); + const foreignExec = await commandBus.execute( + context, + createForeignResult._unsafeUnwrap() + ); + foreignExec._unsafeUnwrap(); + const foreignTable = foreignExec._unsafeUnwrap().table; + const foreignTableId = foreignTable.id().toString(); + const foreignPrimaryFieldId = foreignTable.primaryFieldId().toString(); + + const linkId = `fld${'r'.repeat(16)}`; + const symmetricLinkId = `fld${'s'.repeat(16)}`; + const commandResult = CreateFieldCommand.create({ + baseId: baseId.toString(), + tableId: hostTableId, + field: { + type: 'link', + id: linkId, + name: 'ManyMany Without Lookup', + options: { + relationship: 'manyMany', + foreignTableId, + symmetricFieldId: symmetricLinkId, + }, + }, + }); + commandResult._unsafeUnwrap(); + + const execResult = await commandBus.execute( + context, + commandResult._unsafeUnwrap() + ); + execResult._unsafeUnwrap(); + + const createdLinkRow = await db + .selectFrom('field') + .select(['id', 'options']) + .where('id', '=', linkId) + .executeTakeFirst(); + expect(createdLinkRow).toBeTruthy(); + if (!createdLinkRow) return; + + const createdOptions = JSON.parse(createdLinkRow.options ?? '{}') as Record; + expect(createdOptions.lookupFieldId).toBe(foreignPrimaryFieldId); + + const symmetricRow = await db + .selectFrom('field') + .select(['id', 'options']) + .where('id', '=', symmetricLinkId) + .executeTakeFirst(); + expect(symmetricRow).toBeTruthy(); + if (!symmetricRow) return; + + const symmetricOptions = JSON.parse(symmetricRow.options ?? '{}') as Record; + expect(symmetricOptions.lookupFieldId).toBe(hostPrimaryFieldId); + }); }); diff --git a/packages/v2/test-node/src/commands/DuplicateFieldHandler.db.spec.ts b/packages/v2/test-node/src/commands/DuplicateFieldHandler.db.spec.ts new file mode 100644 index 000000000..8f4694706 --- /dev/null +++ b/packages/v2/test-node/src/commands/DuplicateFieldHandler.db.spec.ts @@ -0,0 +1,92 @@ +import { createV2NodeTestContainer } from '@teable/v2-container-node-test'; +import { v2PostgresDbTokens } from '@teable/v2-adapter-db-postgres-pg'; +import { + ActorId, + CreateTableCommand, + type CreateTableResult, + DuplicateFieldCommand, + type DuplicateFieldResult, + type ICommandBus, + v2CoreTokens, +} from '@teable/v2-core'; +import type { V1TeableDatabase } from '@teable/v2-postgres-schema'; +import type { Kysely } from 'kysely'; +import { beforeEach, describe, expect, it } from 'vitest'; + +import { getV2NodeTestContainer, setV2NodeTestContainer } from '../testkit/v2NodeTestContainer'; + +describe('DuplicateFieldHandler (db)', () => { + beforeEach(async () => { + await getV2NodeTestContainer().dispose(); + setV2NodeTestContainer(await createV2NodeTestContainer()); + }); + + it('respects viewId and updates duplicated field order in target view meta', async () => { + const { container, baseId } = getV2NodeTestContainer(); + const commandBus = container.resolve(v2CoreTokens.commandBus); + const db = container.resolve>(v2PostgresDbTokens.db); + + const context = { actorId: ActorId.create('system')._unsafeUnwrap() }; + + const createTableCommand = CreateTableCommand.create({ + baseId: baseId.toString(), + name: 'Duplicate Field Order', + fields: [ + { type: 'singleLineText', name: 'Name', isPrimary: true }, + { type: 'singleLineText', name: 'Source' }, + { type: 'singleLineText', name: 'Tail' }, + ], + })._unsafeUnwrap(); + + const createTableResult = await commandBus.execute( + context, + createTableCommand + ); + const table = createTableResult._unsafeUnwrap().table; + + const sourceField = table.getFields().find((field) => field.name().toString() === 'Source'); + const tailField = table.getFields().find((field) => field.name().toString() === 'Tail'); + const targetView = table.views()[0]; + expect(sourceField).toBeTruthy(); + expect(tailField).toBeTruthy(); + expect(targetView).toBeTruthy(); + if (!sourceField || !tailField || !targetView) return; + + const duplicateCommand = DuplicateFieldCommand.create({ + baseId: baseId.toString(), + tableId: table.id().toString(), + fieldId: sourceField.id().toString(), + includeRecordValues: true, + newFieldName: 'Source (copy)', + viewId: targetView.id().toString(), + })._unsafeUnwrap(); + + const duplicateResult = await commandBus.execute( + context, + duplicateCommand + ); + const duplicated = duplicateResult._unsafeUnwrap().newField; + + const viewRow = await db + .selectFrom('view') + .select(['column_meta']) + .where('id', '=', targetView.id().toString()) + .executeTakeFirst(); + expect(viewRow).toBeTruthy(); + if (!viewRow) return; + + const columnMeta = JSON.parse(viewRow.column_meta ?? '{}') as Record< + string, + { order?: number } + >; + const sourceOrder = columnMeta[sourceField.id().toString()]?.order; + const tailOrder = columnMeta[tailField.id().toString()]?.order; + const duplicatedOrder = columnMeta[duplicated.id().toString()]?.order; + + expect(typeof sourceOrder).toBe('number'); + expect(typeof tailOrder).toBe('number'); + expect(typeof duplicatedOrder).toBe('number'); + expect((duplicatedOrder as number) > (sourceOrder as number)).toBe(true); + expect((duplicatedOrder as number) < (tailOrder as number)).toBe(true); + }); +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f326dc70..374c60708 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -58,38 +58,38 @@ importers: apps/nestjs-backend: dependencies: '@ai-sdk/amazon-bedrock': - specifier: 4.0.41 - version: 4.0.41(zod@4.1.8) + specifier: 4.0.69 + version: 4.0.69(zod@4.1.8) '@ai-sdk/anthropic': - specifier: 3.0.31 - version: 3.0.31(zod@4.1.8) + specifier: 3.0.50 + version: 3.0.50(zod@4.1.8) '@ai-sdk/azure': - specifier: 3.0.24 - version: 3.0.24(zod@4.1.8) + specifier: 3.0.38 + version: 3.0.38(zod@4.1.8) '@ai-sdk/cohere': - specifier: 3.0.16 - version: 3.0.16(zod@4.1.8) + specifier: 3.0.22 + version: 3.0.22(zod@4.1.8) '@ai-sdk/deepseek': - specifier: 2.0.15 - version: 2.0.15(zod@4.1.8) + specifier: 2.0.21 + version: 2.0.21(zod@4.1.8) '@ai-sdk/google': - specifier: 3.0.18 - version: 3.0.18(zod@4.1.8) + specifier: 3.0.34 + version: 3.0.34(zod@4.1.8) '@ai-sdk/mistral': - specifier: 3.0.16 - version: 3.0.16(zod@4.1.8) + specifier: 3.0.21 + version: 3.0.21(zod@4.1.8) '@ai-sdk/openai': - specifier: 3.0.23 - version: 3.0.23(zod@4.1.8) + specifier: 3.0.37 + version: 3.0.37(zod@4.1.8) '@ai-sdk/openai-compatible': - specifier: 2.0.24 - version: 2.0.24(zod@4.1.8) + specifier: 2.0.31 + version: 2.0.31(zod@4.1.8) '@ai-sdk/togetherai': - specifier: 2.0.27 - version: 2.0.27(zod@4.1.8) + specifier: 2.0.35 + version: 2.0.35(zod@4.1.8) '@ai-sdk/xai': - specifier: 3.0.43 - version: 3.0.43(zod@4.1.8) + specifier: 3.0.60 + version: 3.0.60(zod@4.1.8) '@an-epiphany/websocket-json-stream': specifier: 1.2.0 version: 1.2.0 @@ -151,8 +151,8 @@ importers: specifier: 10.3.5 version: 10.3.5(@nestjs/common@10.3.5(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.1)(rxjs@7.8.1))(@nestjs/core@10.3.5)(reflect-metadata@0.2.1)(rxjs@7.8.1) '@openrouter/ai-sdk-provider': - specifier: 2.1.1 - version: 2.1.1(ai@6.0.62(zod@4.1.8))(zod@4.1.8) + specifier: 2.2.3 + version: 2.2.3(ai@6.0.105(zod@4.1.8))(zod@4.1.8) '@opentelemetry/api': specifier: 1.9.0 version: 1.9.0 @@ -265,8 +265,8 @@ importers: specifier: 1.3.0 version: 1.3.0(valibot@1.1.0(typescript@5.4.3)) ai: - specifier: 6.0.62 - version: 6.0.62(zod@4.1.8) + specifier: 6.0.105 + version: 6.0.105(zod@4.1.8) ajv: specifier: 8.12.0 version: 8.12.0 @@ -401,7 +401,7 @@ importers: version: 2.6.4 ollama-ai-provider-v2: specifier: 3.0.2 - version: 3.0.2(ai@6.0.62(zod@4.1.8))(zod@4.1.8) + version: 3.0.2(ai@6.0.105(zod@4.1.8))(zod@4.1.8) papaparse: specifier: 5.4.1 version: 5.4.1 @@ -4922,68 +4922,68 @@ packages: '@adobe/css-tools@4.4.1': resolution: {integrity: sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==} - '@ai-sdk/amazon-bedrock@4.0.41': - resolution: {integrity: sha512-S0a/vsEy4bTcq+tpTxN5GU5gQBtNp++ML4AEYYcndp5FuKFpdyEjXtvCeI5O0CpXLLPKWrMF8hGvy/Wx3M3XIA==} + '@ai-sdk/amazon-bedrock@4.0.69': + resolution: {integrity: sha512-XdsJnMa1DZAQJ4bRuy97JYF48fSJUZWUpjg4rrDrzKY6wUAOIKpHMHmnGF6bCpd3NcR6E2R7c/HhWyIQAHuuUg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/anthropic@3.0.31': - resolution: {integrity: sha512-rcrtOKbmhFKFxifCYjyFFWvBT2XBUfo6VzD2y2GyG6vZ1XJZoJn7JJe5uLy1bDj4mNUz55cottu5NgI6/NhSuQ==} + '@ai-sdk/anthropic@3.0.50': + resolution: {integrity: sha512-BkCUgGTp/iZJuuFBF1wv7GGnrEJg7X7hqbaa+/t4HTBt9dZn3e6NFn5NhPUvo2p5SreUeHEl0As0r2uaVn3K9Q==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/azure@3.0.24': - resolution: {integrity: sha512-Pt18ozc2IAdHF8YIq5AOl9xo2ZQ6I83OXsIzTFcDYiA5RJq/xm88lAxA3XDMoZZBdqYymBQFHa66JjNH9KpNLw==} + '@ai-sdk/azure@3.0.38': + resolution: {integrity: sha512-ihePWrlsSfCz1sB6tkaRErw9w1f26uKncoVYu3EBjFhvuY0tOIOOcMS3649R/she8wPR/cP5n69t6C8BtjZAFA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/cohere@3.0.16': - resolution: {integrity: sha512-nc6N7EX+K36r5CEoBHU4J06SXiygBh23NEaf/EY+WJMCw7hJEGL7Z3jBPJ+MycFOXStgFZyAGNzBeLd3vNngrw==} + '@ai-sdk/cohere@3.0.22': + resolution: {integrity: sha512-D4TU80rLUD+9eiOd035WMSsQuDBa8/AOcU4NpETfZ7SHZdgGl1WI4EKZAuqAjCfPGgor/QiY+oC1R+ReHFzGQw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/deepseek@2.0.15': - resolution: {integrity: sha512-3wJUjNjGrTZS3K8OEfHD1PZYhzkcXuoL8KIVtzi6WrC5xrDQPjCBPATmdKPV7DgDCF+wujQOaMz5cv40Yg+hog==} + '@ai-sdk/deepseek@2.0.21': + resolution: {integrity: sha512-swIljtTiEBt5fTmnHftb20MnM06eBEANJzEYAUvU1m3yQH+HcduHxwVMLUtf9M7RqpTrBrAJxLtHHP5kPIVSCQ==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/gateway@3.0.29': - resolution: {integrity: sha512-zf6yXT+7DcVGWG7ntxVCYC48X/opsWlO5ePvgH8W9DaEVUtkemqKUEzBqowQ778PkZo8sqMnRfD0+fi9HamRRQ==} + '@ai-sdk/gateway@3.0.59': + resolution: {integrity: sha512-MbtheWHgEFV/8HL1Z6E3hOAsmP73zZlNFg0F0nJAD0Adnjp4J/plqNK00Y896d+dWTw+r0OXzyov9/2wCFjH0Q==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google@3.0.18': - resolution: {integrity: sha512-g36Arlv38wjnqAhNlxMkfTvmWpMbD+FTFoXLppZ8dZhMQbr/UI5dEtFAByU1/lWeDyOmj/uTWzAuRTyJRw7OLA==} + '@ai-sdk/google@3.0.34': + resolution: {integrity: sha512-1tXUr1W5YACXPgtHYWIU3raqMsayp6cMI8NUT4EEzzZSpvHzkkiNWHEr+bGxEGurSUukfo+pE1RKpLwBFOZtJg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/mistral@3.0.16': - resolution: {integrity: sha512-8I/gxXJwghaDLbQQHMBwd61WxYz/PaFUFlG8I38daNYj5qRTMmQ5V10Idi6GJJC0wWEqQkal31lidm9+Y+u6TQ==} + '@ai-sdk/mistral@3.0.21': + resolution: {integrity: sha512-GhLRyfXghnKpt51t8ELU3cXwbCUcGOxZFUQFUZvNBt+y298PlOhaAK6pQtihfpNRGUycrdNotKwVajJm0a6uwg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai-compatible@2.0.24': - resolution: {integrity: sha512-3QrCKpQCn3g6sIMoFGuEroaqk7Xg+qfsohRp4dKszjto5stjBg4SdtOKqHg+CpE3X4woj2O62w2qr5dSekMZeQ==} + '@ai-sdk/openai-compatible@2.0.31': + resolution: {integrity: sha512-e78xiImcTe2aCMQoFbVJluQmUV4XgahOmmehAuRPlcwzRv2KtkvuLCXPC9Xcy2u83e8SimVva9k9G8SvZcnaBA==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@3.0.23': - resolution: {integrity: sha512-vFfFadJH+hbrgI4lhC9H/r8qPzuFJFUwZNS8oMI8KujO/woovbE1EWOOGMRGtNVL8PrhhxBfgJzvOKdux3c1gw==} + '@ai-sdk/openai@3.0.37': + resolution: {integrity: sha512-bcYjT3/58i/C0DN3AnrjiGsAb0kYivZLWWUtgTjsBurHSht/LTEy+w3dw5XQe3FmZwX7Z/mUQCiA3wB/5Kf7ow==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.11': - resolution: {integrity: sha512-y/WOPpcZaBjvNaogy83mBsCRPvbtaK0y1sY9ckRrrbTGMvG2HC/9Y/huqNXKnLAxUIME2PGa2uvF2CDwIsxoXQ==} + '@ai-sdk/provider-utils@4.0.16': + resolution: {integrity: sha512-kBvDqNkt5EwlzF9FujmNhhtl8FYg3e8FO8P5uneKliqfRThWemzBj+wfYr7ZCymAQhTRnwSSz1/SOqhOAwmx9g==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -4998,18 +4998,18 @@ packages: resolution: {integrity: sha512-HrEmNt/BH/hkQ7zpi2o6N3k1ZR1QTb7z85WYhYygiTxOQuaml4CMtHCWRbric5WPU+RNsYI7r1EpyVQMKO1pYw==} engines: {node: '>=18'} - '@ai-sdk/provider@3.0.6': - resolution: {integrity: sha512-hSfoJtLtpMd7YxKM+iTqlJ0ZB+kJ83WESMiWuWrNVey3X8gg97x0OdAAaeAeclZByCX3UdPOTqhvJdK8qYA3ww==} + '@ai-sdk/provider@3.0.8': + resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==} engines: {node: '>=18'} - '@ai-sdk/togetherai@2.0.27': - resolution: {integrity: sha512-Wn6fsjQE1KnB1FCREN96TnQzpJ9nAmYmGHt/qdy632ZQ50Vlo434LXx+bN15OjDN1IqxOhB+HOgvllgCqmiR4g==} + '@ai-sdk/togetherai@2.0.35': + resolution: {integrity: sha512-nTEYviZRpgx5R93E4HFcuUpkK4Cj6JxY+tDkqtC4MlGZfLG6gefrOMHb7CTwv6cLu+CEO6iSyd2uiIa0/pm0Eg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/xai@3.0.43': - resolution: {integrity: sha512-VhfQLACVK4FPGcqvY+6ewfRUOPB7/WhC3okVPJYJhLAzglq7kRZet9pHPEpnzd37X5Y+L+wGDCajid/7OTLCdw==} + '@ai-sdk/xai@3.0.60': + resolution: {integrity: sha512-nDOUyzeepmyyoL5+9LxmwXy3BoX9mZy7cv3BjHPN4Xc+SVFVqL7uj/9m1oLRCNmpwfA/9QBq9kuD+J31EfdhMw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -8450,8 +8450,8 @@ packages: resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} engines: {node: '>=20.0'} - '@openrouter/ai-sdk-provider@2.1.1': - resolution: {integrity: sha512-UypPbVnSExxmG/4Zg0usRiit3auvQVrjUXSyEhm0sZ9GQnW/d8p/bKgCk2neh1W5YyRSo7PNQvCrAEBHZnqQkQ==} + '@openrouter/ai-sdk-provider@2.2.3': + resolution: {integrity: sha512-NovC+BaCfEeJwhToDrs8JeDYXXlJdEyz7lcxkjtyePSE4eoAKik872SyDK0MzXKcz8MRkv7XlNhPI6zz4TQp0g==} engines: {node: '>=18'} peerDependencies: ai: ^6.0.0 @@ -14358,8 +14358,8 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} - ai@6.0.62: - resolution: {integrity: sha512-0ArQPYmSnwoDG1nQ7GQ2XyEtYEWMSK4pVV9S9nsChRY2D6P2H2ntMEDV/CqTF6GTSwJpBJHAOSvsgEqSc7dx5g==} + ai@6.0.105: + resolution: {integrity: sha512-rp+exWtZS3J0DDvZIfetpKCIg7D3cCsvBPoFN3I67IDTs9aoBZDbpecoIkmNLT+U9RBkoEial3OGHRvme23HCw==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -25141,75 +25141,75 @@ snapshots: '@adobe/css-tools@4.4.1': {} - '@ai-sdk/amazon-bedrock@4.0.41(zod@4.1.8)': + '@ai-sdk/amazon-bedrock@4.0.69(zod@4.1.8)': dependencies: - '@ai-sdk/anthropic': 3.0.31(zod@4.1.8) - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/anthropic': 3.0.50(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) '@smithy/eventstream-codec': 4.0.5 '@smithy/util-utf8': 4.0.0 aws4fetch: 1.0.20 zod: 4.1.8 - '@ai-sdk/anthropic@3.0.31(zod@4.1.8)': + '@ai-sdk/anthropic@3.0.50(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/azure@3.0.24(zod@4.1.8)': + '@ai-sdk/azure@3.0.38(zod@4.1.8)': dependencies: - '@ai-sdk/openai': 3.0.23(zod@4.1.8) - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/openai': 3.0.37(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/cohere@3.0.16(zod@4.1.8)': + '@ai-sdk/cohere@3.0.22(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/deepseek@2.0.15(zod@4.1.8)': + '@ai-sdk/deepseek@2.0.21(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/gateway@3.0.29(zod@4.1.8)': + '@ai-sdk/gateway@3.0.59(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) '@vercel/oidc': 3.1.0 zod: 4.1.8 - '@ai-sdk/google@3.0.18(zod@4.1.8)': + '@ai-sdk/google@3.0.34(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/mistral@3.0.16(zod@4.1.8)': + '@ai-sdk/mistral@3.0.21(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/openai-compatible@2.0.24(zod@4.1.8)': + '@ai-sdk/openai-compatible@2.0.31(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/openai@3.0.23(zod@4.1.8)': + '@ai-sdk/openai@3.0.37(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/provider-utils@4.0.11(zod@4.1.8)': + '@ai-sdk/provider-utils@4.0.16(zod@4.1.8)': dependencies: - '@ai-sdk/provider': 3.0.6 + '@ai-sdk/provider': 3.0.8 '@standard-schema/spec': 1.1.0 eventsource-parser: 3.0.6 zod: 4.1.8 @@ -25225,22 +25225,22 @@ snapshots: dependencies: json-schema: 0.4.0 - '@ai-sdk/provider@3.0.6': + '@ai-sdk/provider@3.0.8': dependencies: json-schema: 0.4.0 - '@ai-sdk/togetherai@2.0.27(zod@4.1.8)': + '@ai-sdk/togetherai@2.0.35(zod@4.1.8)': dependencies: - '@ai-sdk/openai-compatible': 2.0.24(zod@4.1.8) - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/openai-compatible': 2.0.31(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 - '@ai-sdk/xai@3.0.43(zod@4.1.8)': + '@ai-sdk/xai@3.0.60(zod@4.1.8)': dependencies: - '@ai-sdk/openai-compatible': 2.0.24(zod@4.1.8) - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/openai-compatible': 2.0.31(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) zod: 4.1.8 '@alloc/quick-lru@5.2.0': {} @@ -28868,9 +28868,9 @@ snapshots: '@oozcitak/util@10.0.0': {} - '@openrouter/ai-sdk-provider@2.1.1(ai@6.0.62(zod@4.1.8))(zod@4.1.8)': + '@openrouter/ai-sdk-provider@2.2.3(ai@6.0.105(zod@4.1.8))(zod@4.1.8)': dependencies: - ai: 6.0.62(zod@4.1.8) + ai: 6.0.105(zod@4.1.8) zod: 4.1.8 '@opentelemetry/api-logs@0.201.1': @@ -36344,11 +36344,11 @@ snapshots: clean-stack: 2.2.0 indent-string: 4.0.0 - ai@6.0.62(zod@4.1.8): + ai@6.0.105(zod@4.1.8): dependencies: - '@ai-sdk/gateway': 3.0.29(zod@4.1.8) - '@ai-sdk/provider': 3.0.6 - '@ai-sdk/provider-utils': 4.0.11(zod@4.1.8) + '@ai-sdk/gateway': 3.0.59(zod@4.1.8) + '@ai-sdk/provider': 3.0.8 + '@ai-sdk/provider-utils': 4.0.16(zod@4.1.8) '@opentelemetry/api': 1.9.0 zod: 4.1.8 @@ -44018,11 +44018,11 @@ snapshots: ohash@2.0.11: {} - ollama-ai-provider-v2@3.0.2(ai@6.0.62(zod@4.1.8))(zod@4.1.8): + ollama-ai-provider-v2@3.0.2(ai@6.0.105(zod@4.1.8))(zod@4.1.8): dependencies: '@ai-sdk/provider': 3.0.2 '@ai-sdk/provider-utils': 4.0.5(zod@4.1.8) - ai: 6.0.62(zod@4.1.8) + ai: 6.0.105(zod@4.1.8) zod: 4.1.8 on-exit-leak-free@2.1.2: {}