sonamu 0.10.12 → 0.10.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/agents/agent.d.ts +1 -1
- package/dist/ai/agents/agent.d.ts.map +1 -1
- package/dist/ai/agents/agent.js +5 -6
- package/dist/ai/agents/types.d.ts +1 -1
- package/dist/ai/agents/types.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/api.js +18 -18
- package/dist/ai/providers/rtzr/error.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/error.js +17 -15
- package/dist/ai/providers/rtzr/model.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/model.js +3 -2
- package/dist/ai/providers/rtzr/options.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/options.js +16 -16
- package/dist/ai/providers/rtzr/provider.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/provider.js +9 -9
- package/dist/ai/providers/rtzr/utils.d.ts.map +1 -1
- package/dist/ai/providers/rtzr/utils.js +1 -1
- package/dist/api/caster.d.ts.map +1 -1
- package/dist/api/caster.js +17 -17
- package/dist/api/code-converters.d.ts +4 -2
- package/dist/api/code-converters.d.ts.map +1 -1
- package/dist/api/code-converters.js +100 -19
- package/dist/api/config.d.ts +16 -1
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +28 -21
- package/dist/api/context.d.ts +2 -2
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +1 -1
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +18 -11
- package/dist/api/http-validator.d.ts +36 -0
- package/dist/api/http-validator.d.ts.map +1 -0
- package/dist/api/http-validator.js +72 -0
- package/dist/api/index.js +6 -4
- package/dist/api/sonamu.d.ts +59 -20
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +250 -106
- package/dist/api/websocket-helpers.d.ts +7 -5
- package/dist/api/websocket-helpers.d.ts.map +1 -1
- package/dist/api/websocket-helpers.js +6 -6
- package/dist/auth/audit-log/builders.d.ts.map +1 -1
- package/dist/auth/audit-log/builders.js +1 -1
- package/dist/auth/audit-log/client-ip.d.ts +1 -1
- package/dist/auth/audit-log/client-ip.d.ts.map +1 -1
- package/dist/auth/audit-log/client-ip.js +4 -2
- package/dist/auth/audit-log/events.d.ts +5 -1
- package/dist/auth/audit-log/events.d.ts.map +1 -1
- package/dist/auth/audit-log/events.js +1 -1
- package/dist/auth/audit-log/plugin.d.ts +0 -8
- package/dist/auth/audit-log/plugin.d.ts.map +1 -1
- package/dist/auth/audit-log/plugin.js +48 -52
- package/dist/auth/audit-log-ingestor.d.ts.map +1 -1
- package/dist/auth/audit-log-ingestor.js +16 -12
- package/dist/auth/auth-generator.d.ts.map +1 -1
- package/dist/auth/auth-generator.js +1 -1
- package/dist/auth/better-auth-request.d.ts.map +1 -1
- package/dist/auth/better-auth-request.js +6 -5
- package/dist/auth/knex-adapter.js +1 -1
- package/dist/auth/plugins/entity-definitions/index.d.ts +13 -1
- package/dist/auth/plugins/entity-definitions/index.d.ts.map +1 -1
- package/dist/auth/plugins/entity-definitions/index.js +1 -1
- package/dist/auth/plugins/wrappers/admin.d.ts +1 -1
- package/dist/bin/build-config.d.ts +25 -0
- package/dist/bin/build-config.d.ts.map +1 -1
- package/dist/bin/build-config.js +105 -2
- package/dist/bin/cli.js +131 -27
- package/dist/bin/compiler-policy.d.ts +3 -0
- package/dist/bin/compiler-policy.d.ts.map +1 -0
- package/dist/bin/compiler-policy.js +24 -0
- package/dist/bin/fixture.d.ts.map +1 -1
- package/dist/bin/fixture.js +5 -3
- package/dist/bin/test-command.d.ts +22 -1
- package/dist/bin/test-command.d.ts.map +1 -1
- package/dist/bin/test-command.js +18 -10
- package/dist/bin/ts-loader-registration.d.ts +7 -1
- package/dist/bin/ts-loader-registration.d.ts.map +1 -1
- package/dist/bin/ts-loader-registration.js +13 -4
- package/dist/cache/decorator.d.ts.map +1 -1
- package/dist/cache/decorator.js +11 -4
- package/dist/compress/compress.d.ts.map +1 -1
- package/dist/compress/compress.js +1 -1
- package/dist/cone/cone-generator.d.ts +14 -1
- package/dist/cone/cone-generator.d.ts.map +1 -1
- package/dist/cone/cone-generator.js +13 -9
- package/dist/database/_batch_update.js +1 -1
- package/dist/database/base-model.d.ts +22 -10
- package/dist/database/base-model.d.ts.map +1 -1
- package/dist/database/base-model.js +26 -16
- package/dist/database/base-model.types.d.ts +15 -3
- package/dist/database/base-model.types.d.ts.map +1 -1
- package/dist/database/db.d.ts +12 -2
- package/dist/database/db.d.ts.map +1 -1
- package/dist/database/db.js +10 -7
- package/dist/database/knex.d.ts.map +1 -1
- package/dist/database/knex.js +17 -14
- package/dist/database/puri.d.ts +11 -9
- package/dist/database/puri.d.ts.map +1 -1
- package/dist/database/puri.js +93 -79
- package/dist/database/puri.types.d.ts +21 -21
- package/dist/database/puri.types.d.ts.map +1 -1
- package/dist/database/puri.types.js +1 -1
- package/dist/database/upsert-builder.d.ts +12 -10
- package/dist/database/upsert-builder.d.ts.map +1 -1
- package/dist/database/upsert-builder.js +20 -12
- package/dist/dict/sd.d.ts.map +1 -1
- package/dist/dict/sd.js +1 -1
- package/dist/dict/sonamu-dictionary.d.ts.map +1 -1
- package/dist/dict/sonamu-dictionary.js +1 -1
- package/dist/dict/utils.d.ts.map +1 -1
- package/dist/dict/utils.js +7 -2
- package/dist/entity/entity-manager.d.ts +13 -4
- package/dist/entity/entity-manager.d.ts.map +1 -1
- package/dist/entity/entity-manager.js +19 -11
- package/dist/entity/entity-template-cone.d.ts +73 -5
- package/dist/entity/entity-template-cone.d.ts.map +1 -1
- package/dist/entity/entity-template-cone.js +4 -2
- package/dist/entity/entity.d.ts +6 -2
- package/dist/entity/entity.d.ts.map +1 -1
- package/dist/entity/entity.js +30 -28
- package/dist/env.d.ts +3 -1
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +1 -1
- package/dist/exceptions/error-handler.d.ts.map +1 -1
- package/dist/exceptions/error-handler.js +7 -2
- package/dist/exceptions/so-exceptions.d.ts +24 -20
- package/dist/exceptions/so-exceptions.d.ts.map +1 -1
- package/dist/exceptions/so-exceptions.js +4 -2
- package/dist/filter/utils.d.ts +7 -2
- package/dist/filter/utils.d.ts.map +1 -1
- package/dist/filter/utils.js +8 -6
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -6
- package/dist/logger/configure.d.ts.map +1 -1
- package/dist/logger/configure.js +10 -10
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +50 -46
- package/dist/migration/index-where-predicate.d.ts.map +1 -1
- package/dist/migration/index-where-predicate.js +22 -8
- package/dist/migration/migration-set.d.ts.map +1 -1
- package/dist/migration/migration-set.js +1 -1
- package/dist/migration/migrator.d.ts +3 -2
- package/dist/migration/migrator.d.ts.map +1 -1
- package/dist/migration/migrator.js +27 -21
- package/dist/migration/postgresql-schema-reader.d.ts.map +1 -1
- package/dist/migration/postgresql-schema-reader.js +51 -36
- package/dist/migration/slack-confirm.d.ts.map +1 -1
- package/dist/migration/slack-confirm.js +1 -1
- package/dist/naite/naite-reporter.js +2 -2
- package/dist/naite/naite.d.ts +74 -15
- package/dist/naite/naite.d.ts.map +1 -1
- package/dist/naite/naite.js +5 -19
- package/dist/runtime-type.d.ts +6 -0
- package/dist/runtime-type.d.ts.map +1 -0
- package/dist/runtime-type.js +26 -0
- package/dist/ssr/hmr-opt-out.d.ts +26 -0
- package/dist/ssr/hmr-opt-out.d.ts.map +1 -0
- package/dist/ssr/hmr-opt-out.js +59 -0
- package/dist/ssr/renderer.d.ts.map +1 -1
- package/dist/ssr/renderer.js +4 -1
- package/dist/storage/base-file.js +14 -14
- package/dist/storage/buffered-file.d.ts +2 -2
- package/dist/storage/buffered-file.d.ts.map +1 -1
- package/dist/storage/buffered-file.js +12 -12
- package/dist/storage/s3-driver.d.ts.map +1 -1
- package/dist/storage/s3-driver.js +1 -1
- package/dist/storage/uploaded-file.d.ts +2 -2
- package/dist/storage/uploaded-file.d.ts.map +1 -1
- package/dist/storage/uploaded-file.js +8 -8
- package/dist/stream/sse.js +11 -11
- package/dist/stream/ws-core.d.ts +1 -1
- package/dist/stream/ws-core.d.ts.map +1 -1
- package/dist/stream/ws-delivery.d.ts +1 -1
- package/dist/stream/ws-delivery.d.ts.map +1 -1
- package/dist/stream/ws-delivery.js +6 -4
- package/dist/stream/ws-local-connection-store.d.ts.map +1 -1
- package/dist/stream/ws-local-connection-store.js +4 -2
- package/dist/stream/ws-presence-store.js +1 -1
- package/dist/stream/ws-registry.d.ts +4 -4
- package/dist/stream/ws-registry.d.ts.map +1 -1
- package/dist/stream/ws-registry.js +4 -2
- package/dist/stream/ws-telemetry.d.ts +16 -12
- package/dist/stream/ws-telemetry.d.ts.map +1 -1
- package/dist/stream/ws-telemetry.js +22 -18
- package/dist/stream/ws.d.ts +18 -12
- package/dist/stream/ws.d.ts.map +1 -1
- package/dist/stream/ws.js +26 -22
- package/dist/syncer/api-parser.js +1 -1
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +7 -8
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +13 -14
- package/dist/syncer/entity-operations.d.ts.map +1 -1
- package/dist/syncer/entity-operations.js +5 -6
- package/dist/syncer/file-copy.d.ts +5 -0
- package/dist/syncer/file-copy.d.ts.map +1 -0
- package/dist/syncer/file-copy.js +36 -0
- package/dist/syncer/file-patterns.d.ts +1 -0
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +5 -2
- package/dist/syncer/file-tracking.d.ts.map +1 -1
- package/dist/syncer/file-tracking.js +5 -4
- package/dist/syncer/filesystem-dependencies.d.ts +15 -0
- package/dist/syncer/filesystem-dependencies.d.ts.map +1 -0
- package/dist/syncer/filesystem-dependencies.js +53 -0
- package/dist/syncer/module-loader.d.ts +1 -1
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +6 -4
- package/dist/syncer/syncer-actions.d.ts +4 -0
- package/dist/syncer/syncer-actions.d.ts.map +1 -1
- package/dist/syncer/syncer-actions.js +34 -17
- package/dist/syncer/syncer.d.ts +17 -6
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +71 -29
- package/dist/syncer/watcher.d.ts.map +1 -1
- package/dist/syncer/watcher.js +3 -3
- package/dist/tasks/decorator.d.ts +6 -6
- package/dist/tasks/decorator.d.ts.map +1 -1
- package/dist/tasks/decorator.js +4 -4
- package/dist/tasks/step-wrapper.d.ts +6 -4
- package/dist/tasks/step-wrapper.d.ts.map +1 -1
- package/dist/tasks/step-wrapper.js +5 -5
- package/dist/tasks/workflow-manager.d.ts.map +1 -1
- package/dist/tasks/workflow-manager.js +13 -7
- package/dist/template/entity-converter.d.ts +1 -1
- package/dist/template/entity-converter.d.ts.map +1 -1
- package/dist/template/entity-converter.js +2 -2
- package/dist/template/helpers.d.ts +8 -6
- package/dist/template/helpers.d.ts.map +1 -1
- package/dist/template/helpers.js +1 -1
- package/dist/template/implementations/generated.template.d.ts.map +1 -1
- package/dist/template/implementations/generated.template.js +4 -4
- package/dist/template/implementations/generated_http.template.d.ts +7 -4
- package/dist/template/implementations/generated_http.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_http.template.js +21 -21
- package/dist/template/implementations/generated_sso.template.d.ts.map +1 -1
- package/dist/template/implementations/generated_sso.template.js +6 -3
- package/dist/template/implementations/http_validators.template.d.ts +18 -0
- package/dist/template/implementations/http_validators.template.d.ts.map +1 -0
- package/dist/template/implementations/http_validators.template.js +127 -0
- package/dist/template/implementations/model.template.d.ts.map +1 -1
- package/dist/template/implementations/model.template.js +1 -1
- package/dist/template/implementations/queries.template.js +1 -1
- package/dist/template/implementations/sd.template.d.ts.map +1 -1
- package/dist/template/implementations/sd.template.js +79 -39
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/services.template.js +6 -4
- package/dist/template/implementations/view_form.template.d.ts +6 -1
- package/dist/template/implementations/view_form.template.d.ts.map +1 -1
- package/dist/template/implementations/view_form.template.js +23 -15
- package/dist/template/implementations/view_list.template.d.ts.map +1 -1
- package/dist/template/implementations/view_list.template.js +11 -6
- package/dist/template/template-manager.d.ts.map +1 -1
- package/dist/template/template-manager.js +9 -7
- package/dist/template/template-types.d.ts +12 -5
- package/dist/template/template-types.d.ts.map +1 -1
- package/dist/template/template-types.js +1 -1
- package/dist/template/template.d.ts +2 -2
- package/dist/template/template.d.ts.map +1 -1
- package/dist/template/template.js +6 -4
- package/dist/template/zod-converter.d.ts +0 -19
- package/dist/template/zod-converter.d.ts.map +1 -1
- package/dist/template/zod-converter.js +100 -84
- package/dist/testing/_relation-graph.d.ts.map +1 -1
- package/dist/testing/_relation-graph.js +2 -1
- package/dist/testing/bootstrap.d.ts.map +1 -1
- package/dist/testing/bootstrap.js +9 -6
- package/dist/testing/data-explorer.d.ts +32 -7
- package/dist/testing/data-explorer.d.ts.map +1 -1
- package/dist/testing/data-explorer.js +77 -31
- package/dist/testing/dev-test-routes.d.ts +8 -1
- package/dist/testing/dev-test-routes.d.ts.map +1 -1
- package/dist/testing/dev-test-routes.js +125 -108
- package/dist/testing/dev-vitest-manager.d.ts +54 -8
- package/dist/testing/dev-vitest-manager.d.ts.map +1 -1
- package/dist/testing/dev-vitest-manager.js +24 -9
- package/dist/testing/faker-mappings.d.ts +412 -1
- package/dist/testing/faker-mappings.d.ts.map +1 -1
- package/dist/testing/faker-mappings.js +1 -1
- package/dist/testing/filesystem.d.ts +2 -0
- package/dist/testing/filesystem.d.ts.map +1 -0
- package/dist/testing/filesystem.js +7 -0
- package/dist/testing/fixture-generator.d.ts +25 -8
- package/dist/testing/fixture-generator.d.ts.map +1 -1
- package/dist/testing/fixture-generator.js +132 -73
- package/dist/testing/fixture-loader.d.ts +3 -1
- package/dist/testing/fixture-loader.d.ts.map +1 -1
- package/dist/testing/fixture-loader.js +1 -20
- package/dist/testing/fixture-manager.d.ts +8 -7
- package/dist/testing/fixture-manager.d.ts.map +1 -1
- package/dist/testing/fixture-manager.js +91 -59
- package/dist/testing/global-setup.d.ts.map +1 -1
- package/dist/testing/global-setup.js +5 -2
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +6 -3
- package/dist/types/types.d.ts +101 -99
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +234 -225
- package/dist/ui/ai-api.d.ts.map +1 -1
- package/dist/ui/ai-api.js +1 -1
- package/dist/ui/ai-client.d.ts.map +1 -1
- package/dist/ui/ai-client.js +28 -18
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +135 -128
- package/dist/ui/async-route.d.ts +3 -0
- package/dist/ui/async-route.d.ts.map +1 -0
- package/dist/ui/async-route.js +12 -0
- package/dist/ui/cdd-service.d.ts +9 -7
- package/dist/ui/cdd-service.d.ts.map +1 -1
- package/dist/ui/cdd-service.js +7 -5
- package/dist/ui/migrations-api.d.ts.map +1 -1
- package/dist/ui/migrations-api.js +17 -15
- package/dist/ui-web/assets/index-DV1AAq6W.js +178 -0
- package/dist/ui-web/index.html +1 -1
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +7 -5
- package/dist/utils/fs-utils.d.ts +3 -3
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +6 -6
- package/dist/utils/model.d.ts +3 -5
- package/dist/utils/model.d.ts.map +1 -1
- package/dist/utils/model.js +1 -1
- package/dist/utils/object-utils.d.ts +1 -1
- package/dist/utils/object-utils.d.ts.map +1 -1
- package/dist/utils/object-utils.js +17 -16
- package/dist/utils/process-utils.d.ts.map +1 -1
- package/dist/utils/process-utils.js +4 -2
- package/dist/utils/runtime-value.d.ts +13 -0
- package/dist/utils/runtime-value.d.ts.map +1 -0
- package/dist/utils/runtime-value.js +40 -0
- package/dist/utils/sql-parser.d.ts +8 -1
- package/dist/utils/sql-parser.d.ts.map +1 -1
- package/dist/utils/sql-parser.js +6 -3
- package/dist/utils/type-utils.d.ts.map +1 -1
- package/dist/utils/type-utils.js +10 -8
- package/dist/utils/utils.d.ts +2 -2
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +11 -8
- package/dist/utils/zod-error.d.ts.map +1 -1
- package/dist/utils/zod-error.js +7 -4
- package/dist/vector/chunking.d.ts.map +1 -1
- package/dist/vector/chunking.js +1 -1
- package/dist/vector/embedding.d.ts.map +1 -1
- package/dist/vector/embedding.js +1 -1
- package/dist/vector/types.d.ts +3 -2
- package/dist/vector/types.d.ts.map +1 -1
- package/package.json +5 -3
- package/src/ai/agents/agent.ts +5 -5
- package/src/ai/agents/types.ts +1 -1
- package/src/ai/providers/rtzr/__tests__/model.test.ts +2 -2
- package/src/ai/providers/rtzr/error.ts +5 -3
- package/src/ai/providers/rtzr/model.ts +3 -2
- package/src/ai/providers/rtzr/options.ts +10 -5
- package/src/ai/providers/rtzr/provider.ts +10 -10
- package/src/ai/providers/rtzr/utils.ts +3 -1
- package/src/api/__tests__/config.test.ts +11 -21
- package/src/api/__tests__/sonamu.http-validator.test.ts +512 -0
- package/src/api/__tests__/sonamu.websocket.test.ts +51 -41
- package/src/api/__tests__/zod-compiler-policy.test.ts +95 -0
- package/src/api/caster.ts +6 -8
- package/src/api/code-converters.ts +136 -36
- package/src/api/config.ts +62 -4
- package/src/api/context.ts +3 -3
- package/src/api/decorators.ts +28 -17
- package/src/api/http-validator.ts +149 -0
- package/src/api/sonamu.ts +459 -152
- package/src/api/websocket-helpers.ts +24 -17
- package/src/auth/audit-log/builders.ts +3 -2
- package/src/auth/audit-log/client-ip.ts +4 -2
- package/src/auth/audit-log/events.ts +15 -1
- package/src/auth/audit-log/plugin.ts +129 -200
- package/src/auth/audit-log-ingestor.ts +19 -15
- package/src/auth/auth-generator.ts +10 -5
- package/src/auth/better-auth-request.ts +4 -3
- package/src/auth/knex-adapter.ts +8 -2
- package/src/auth/plugins/entity-definitions/index.ts +6 -5
- package/src/bin/__tests__/http-validator-benchmark.test.ts +94 -0
- package/src/bin/__tests__/test-command.test.ts +9 -15
- package/src/bin/__tests__/ts-loader-register.test.ts +15 -17
- package/src/bin/__tests__/zod-compiler-build.test.ts +307 -0
- package/src/bin/build-config.ts +167 -0
- package/src/bin/cli.ts +153 -36
- package/src/bin/compiler-policy.ts +35 -0
- package/src/bin/fixture.ts +14 -3
- package/src/bin/test-command.ts +74 -29
- package/src/bin/ts-loader-registration.ts +22 -4
- package/src/cache/decorator.ts +10 -3
- package/src/compress/compress.ts +17 -4
- package/src/cone/cone-generator.ts +34 -6
- package/src/database/__tests__/db.test.ts +1 -0
- package/src/database/__tests__/puri.test.ts +16 -15
- package/src/database/__tests__/transaction-scope.test.ts +5 -0
- package/src/database/_batch_update.ts +1 -0
- package/src/database/base-model.ts +81 -50
- package/src/database/base-model.types.ts +6 -6
- package/src/database/db.ts +29 -19
- package/src/database/knex.ts +30 -17
- package/src/database/puri-subset.test-d.ts +17 -0
- package/src/database/puri.ts +181 -143
- package/src/database/puri.types.test-d.ts +31 -1
- package/src/database/puri.types.ts +23 -21
- package/src/database/upsert-builder.ts +75 -53
- package/src/dict/sd.ts +15 -5
- package/src/dict/sonamu-dictionary.ts +6 -6
- package/src/dict/utils.ts +9 -1
- package/src/entity/entity-manager.ts +26 -9
- package/src/entity/entity-template-cone.ts +5 -10
- package/src/entity/entity.ts +50 -34
- package/src/env.ts +7 -3
- package/src/exceptions/error-handler.ts +17 -2
- package/src/exceptions/so-exceptions.ts +26 -20
- package/src/filter/utils.ts +21 -11
- package/src/index.ts +3 -0
- package/src/logger/configure.ts +26 -18
- package/src/migration/__tests__/migrator.test.ts +50 -57
- package/src/migration/code-generation.ts +132 -104
- package/src/migration/index-where-predicate.ts +51 -24
- package/src/migration/migration-set.ts +11 -5
- package/src/migration/migrator.ts +68 -41
- package/src/migration/postgresql-schema-reader.ts +52 -47
- package/src/migration/slack-confirm.ts +17 -15
- package/src/naite/naite-reporter.ts +1 -1
- package/src/naite/naite.ts +97 -24
- package/src/runtime-type.ts +34 -0
- package/src/ssr/hmr-opt-out.ts +78 -0
- package/src/ssr/renderer.ts +6 -0
- package/src/storage/base-file.ts +13 -13
- package/src/storage/buffered-file.ts +11 -11
- package/src/storage/s3-driver.ts +4 -1
- package/src/storage/uploaded-file.ts +8 -8
- package/src/stream/__tests__/ws-contracts.test.ts +4 -2
- package/src/stream/__tests__/ws-telemetry.test.ts +1 -1
- package/src/stream/__tests__/ws.test.ts +30 -6
- package/src/stream/sse.ts +12 -11
- package/src/stream/ws-core.ts +1 -1
- package/src/stream/ws-delivery.ts +16 -7
- package/src/stream/ws-local-connection-store.ts +2 -3
- package/src/stream/ws-presence-store.ts +6 -1
- package/src/stream/ws-registry.ts +16 -7
- package/src/stream/ws-telemetry.ts +66 -43
- package/src/stream/ws.ts +73 -39
- package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +3 -2
- package/src/syncer/__tests__/http-validator-registry.test.ts +137 -0
- package/src/syncer/api-parser.ts +67 -27
- package/src/syncer/checksum.ts +17 -11
- package/src/syncer/code-generator.ts +25 -17
- package/src/syncer/entity-operations.ts +3 -5
- package/src/syncer/file-copy.ts +46 -0
- package/src/syncer/file-patterns.ts +11 -8
- package/src/syncer/file-tracking.ts +3 -4
- package/src/syncer/filesystem-dependencies.ts +73 -0
- package/src/syncer/module-loader.ts +8 -4
- package/src/syncer/syncer-actions.ts +56 -18
- package/src/syncer/syncer.ts +116 -43
- package/src/syncer/watcher.ts +8 -4
- package/src/tasks/decorator.ts +20 -12
- package/src/tasks/step-wrapper.ts +19 -9
- package/src/tasks/workflow-manager.ts +15 -9
- package/src/template/__tests__/http_validators.template.test.ts +160 -0
- package/src/template/__tests__/services.template.mutation.test.ts +24 -23
- package/src/template/__tests__/services.template.websocket.test.ts +21 -25
- package/src/template/entity-converter.ts +5 -2
- package/src/template/helpers.ts +8 -9
- package/src/template/implementations/generated.template.ts +5 -4
- package/src/template/implementations/generated_http.template.ts +61 -15
- package/src/template/implementations/generated_sso.template.ts +15 -4
- package/src/template/implementations/http_validators.template.ts +175 -0
- package/src/template/implementations/model.template.ts +3 -1
- package/src/template/implementations/sd.template.ts +81 -41
- package/src/template/implementations/services.template.ts +2 -2
- package/src/template/implementations/view_form.template.ts +56 -39
- package/src/template/implementations/view_list.template.ts +31 -23
- package/src/template/template-manager.ts +15 -13
- package/src/template/template-types.ts +13 -5
- package/src/template/template.ts +4 -3
- package/src/template/zod-converter.ts +206 -91
- package/src/testing/__tests__/dev-test-routes.test.ts +85 -25
- package/src/testing/__tests__/dev-vitest-manager.test.ts +15 -15
- package/src/testing/_relation-graph.ts +4 -1
- package/src/testing/bootstrap.ts +12 -5
- package/src/testing/data-explorer.ts +102 -53
- package/src/testing/dev-test-routes.ts +87 -50
- package/src/testing/dev-vitest-manager.ts +88 -32
- package/src/testing/faker-mappings.ts +2 -2
- package/src/testing/filesystem.ts +1 -0
- package/src/testing/fixture-generator.ts +191 -131
- package/src/testing/fixture-loader.ts +5 -1
- package/src/testing/fixture-manager.ts +129 -90
- package/src/testing/global-setup.ts +7 -3
- package/src/testing/index.ts +5 -0
- package/src/types/__tests__/entity-json-schema-search-text.test.ts +9 -3
- package/src/types/types.ts +184 -158
- package/src/ui/ai-api.ts +9 -7
- package/src/ui/ai-client.ts +61 -56
- package/src/ui/api.ts +727 -616
- package/src/ui/async-route.ts +4 -0
- package/src/ui/cdd-service.ts +35 -12
- package/src/ui/migrations-api.ts +63 -51
- package/src/utils/formatter.ts +7 -3
- package/src/utils/fs-utils.ts +5 -5
- package/src/utils/model.ts +4 -5
- package/src/utils/object-utils.ts +32 -22
- package/src/utils/process-utils.ts +4 -1
- package/src/utils/runtime-value.ts +43 -0
- package/src/utils/sql-parser.ts +13 -6
- package/src/utils/type-utils.ts +9 -7
- package/src/utils/utils.ts +19 -21
- package/src/utils/zod-error.ts +4 -2
- package/src/vector/chunking.ts +6 -1
- package/src/vector/embedding.ts +2 -1
- package/src/vector/types.ts +4 -2
- package/tsdown.api.config.ts +5 -2
- package/dist/ui-web/assets/index-C0m1pk6K.js +0 -177
package/src/database/puri.ts
CHANGED
|
@@ -9,6 +9,12 @@ import { type Knex } from "knex";
|
|
|
9
9
|
import { EntityManager } from "../entity/entity-manager";
|
|
10
10
|
import { type TableSpec } from "../entity/entity-manager";
|
|
11
11
|
import { Naite } from "../naite/naite";
|
|
12
|
+
import {
|
|
13
|
+
isFunctionValue,
|
|
14
|
+
isNumberValue,
|
|
15
|
+
isObjectValue,
|
|
16
|
+
isStringValue,
|
|
17
|
+
} from "../utils/runtime-value";
|
|
12
18
|
import { type ClearStatements } from "./puri-subset.types";
|
|
13
19
|
import {
|
|
14
20
|
type AvailableColumns,
|
|
@@ -30,6 +36,7 @@ import {
|
|
|
30
36
|
type ResultAvailableColumns,
|
|
31
37
|
type SelectAllResult,
|
|
32
38
|
type SelectObject,
|
|
39
|
+
type SelectValue,
|
|
33
40
|
type SingleTableValue,
|
|
34
41
|
type SqlExpression,
|
|
35
42
|
type TsHighlightOptions,
|
|
@@ -79,7 +86,7 @@ type JoinRegistration = {
|
|
|
79
86
|
|
|
80
87
|
type CorrelationRegistration = FromRegistration | JoinRegistration;
|
|
81
88
|
|
|
82
|
-
function
|
|
89
|
+
export function parseFuzzyOperator(operator?: string): FuzzyOperator {
|
|
83
90
|
const normalized = operator?.trim() ?? "<%";
|
|
84
91
|
const fuzzyOperator = FUZZY_OPERATORS.find((candidate) => candidate === normalized);
|
|
85
92
|
|
|
@@ -90,7 +97,7 @@ function normalizeFuzzyOperator(operator?: string): FuzzyOperator {
|
|
|
90
97
|
return fuzzyOperator;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
|
-
function serializeJsonSupersetValue(value:
|
|
100
|
+
function serializeJsonSupersetValue<Value>(value: Value): string {
|
|
94
101
|
const serialized = JSON.stringify(value);
|
|
95
102
|
|
|
96
103
|
if (serialized === undefined) {
|
|
@@ -102,11 +109,11 @@ function serializeJsonSupersetValue(value: unknown): string {
|
|
|
102
109
|
return serialized;
|
|
103
110
|
}
|
|
104
111
|
|
|
105
|
-
function serializeJsonColumnValue(
|
|
112
|
+
function serializeJsonColumnValue<Value>(
|
|
106
113
|
tableSpec: TableSpec | null,
|
|
107
114
|
column: string,
|
|
108
|
-
value:
|
|
109
|
-
):
|
|
115
|
+
value: Value,
|
|
116
|
+
): Value | string {
|
|
110
117
|
if (!tableSpec?.jsonColumns.includes(column) || value === undefined || value === null) {
|
|
111
118
|
return value;
|
|
112
119
|
}
|
|
@@ -142,15 +149,23 @@ function formatNullsSuffix(nulls?: PuriOrderByNulls): string {
|
|
|
142
149
|
return ` NULLS ${nulls.toUpperCase()}`;
|
|
143
150
|
}
|
|
144
151
|
|
|
145
|
-
function isOrderByEntries(
|
|
152
|
+
function isOrderByEntries<Value>(
|
|
153
|
+
value: Value,
|
|
154
|
+
): value is Value & readonly PuriOrderByRuntimeEntry[] {
|
|
146
155
|
return Array.isArray(value);
|
|
147
156
|
}
|
|
148
157
|
|
|
149
|
-
function isSqlExpression(value:
|
|
150
|
-
return
|
|
158
|
+
function isSqlExpression<Value>(value: Value): value is Value & PuriOrderByExpression {
|
|
159
|
+
return isObjectValue(value) && "_type" in value && value["_type"] === "sql_expression";
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function isNestedSelectObject<TTables extends object>(
|
|
163
|
+
value: SelectValue<TTables> | SelectObject<TTables>,
|
|
164
|
+
): value is SelectObject<TTables> {
|
|
165
|
+
return isObjectValue(value) && !("_type" in value);
|
|
151
166
|
}
|
|
152
167
|
|
|
153
|
-
export class Puri<TSchema, TTables extends
|
|
168
|
+
export class Puri<TSchema, TTables extends object, TResult> {
|
|
154
169
|
private knexQuery: Knex.QueryBuilder;
|
|
155
170
|
private tableSpec: TableSpec | null = null;
|
|
156
171
|
private correlationRegistry = new Map<string, CorrelationRegistration>();
|
|
@@ -162,7 +177,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
162
177
|
public knex: Knex,
|
|
163
178
|
tableNameOrSource: any,
|
|
164
179
|
) {
|
|
165
|
-
if (
|
|
180
|
+
if (isStringValue(tableNameOrSource)) {
|
|
166
181
|
// Case: new Puri(knex, "users")
|
|
167
182
|
this.knexQuery = this.knex(tableNameOrSource).from(tableNameOrSource);
|
|
168
183
|
this.tableSpec = this.safeGetTableSpec(tableNameOrSource);
|
|
@@ -171,14 +186,14 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
171
186
|
alias: tableNameOrSource,
|
|
172
187
|
table: tableNameOrSource,
|
|
173
188
|
});
|
|
174
|
-
} else if (
|
|
189
|
+
} else if (isObjectValue(tableNameOrSource)) {
|
|
175
190
|
const entries = Object.entries(tableNameOrSource);
|
|
176
191
|
if (entries.length !== 1) {
|
|
177
192
|
throw new Error("Table spec must have exactly one entry");
|
|
178
193
|
}
|
|
179
194
|
assert(entries[0]);
|
|
180
195
|
const [alias, source] = entries[0];
|
|
181
|
-
if (
|
|
196
|
+
if (isStringValue(source)) {
|
|
182
197
|
this.knexQuery = this.knex(source).from({ [alias]: source });
|
|
183
198
|
this.tableSpec = this.safeGetTableSpec(source);
|
|
184
199
|
this.correlationRegistry.set(alias, { kind: "from", alias, table: source });
|
|
@@ -272,7 +287,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
272
287
|
column: string | SqlExpression<"string">,
|
|
273
288
|
query: string,
|
|
274
289
|
): SqlExpression<"number"> {
|
|
275
|
-
if (
|
|
290
|
+
if (isStringValue(column)) {
|
|
276
291
|
return {
|
|
277
292
|
_type: "sql_expression",
|
|
278
293
|
_return: "number",
|
|
@@ -284,8 +299,8 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
284
299
|
return {
|
|
285
300
|
_type: "sql_expression",
|
|
286
301
|
_return: "number",
|
|
287
|
-
_sql: `word_similarity(?, ${column
|
|
288
|
-
_params: [query, ...column
|
|
302
|
+
_sql: `word_similarity(?, ${column["_sql"]})`,
|
|
303
|
+
_params: [query, ...column["_params"]],
|
|
289
304
|
};
|
|
290
305
|
}
|
|
291
306
|
|
|
@@ -293,7 +308,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
293
308
|
column: string | SqlExpression<"string">,
|
|
294
309
|
query: string,
|
|
295
310
|
): SqlExpression<"number"> {
|
|
296
|
-
if (
|
|
311
|
+
if (isStringValue(column)) {
|
|
297
312
|
return {
|
|
298
313
|
_type: "sql_expression",
|
|
299
314
|
_return: "number",
|
|
@@ -305,8 +320,8 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
305
320
|
return {
|
|
306
321
|
_type: "sql_expression",
|
|
307
322
|
_return: "number",
|
|
308
|
-
_sql: `similarity(${column
|
|
309
|
-
_params: [...column
|
|
323
|
+
_sql: `similarity(${column["_sql"]}, ?)`,
|
|
324
|
+
_params: [...column["_params"], query],
|
|
310
325
|
};
|
|
311
326
|
}
|
|
312
327
|
|
|
@@ -314,7 +329,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
314
329
|
column: string | SqlExpression<"string">,
|
|
315
330
|
query: string,
|
|
316
331
|
): SqlExpression<"number"> {
|
|
317
|
-
if (
|
|
332
|
+
if (isStringValue(column)) {
|
|
318
333
|
return {
|
|
319
334
|
_type: "sql_expression",
|
|
320
335
|
_return: "number",
|
|
@@ -326,8 +341,8 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
326
341
|
return {
|
|
327
342
|
_type: "sql_expression",
|
|
328
343
|
_return: "number",
|
|
329
|
-
_sql: `strict_word_similarity(?, ${column
|
|
330
|
-
_params: [query, ...column
|
|
344
|
+
_sql: `strict_word_similarity(?, ${column["_sql"]})`,
|
|
345
|
+
_params: [query, ...column["_params"]],
|
|
331
346
|
};
|
|
332
347
|
}
|
|
333
348
|
|
|
@@ -392,7 +407,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
392
407
|
query: string,
|
|
393
408
|
options?: TsRankOptions,
|
|
394
409
|
): SqlExpression<"number"> {
|
|
395
|
-
return Puri
|
|
410
|
+
return Puri["_tsRank"]("ts_rank", column, query, options);
|
|
396
411
|
}
|
|
397
412
|
|
|
398
413
|
// ts_rank_cd
|
|
@@ -401,7 +416,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
401
416
|
query: string,
|
|
402
417
|
options?: TsRankOptions,
|
|
403
418
|
): SqlExpression<"number"> {
|
|
404
|
-
return Puri
|
|
419
|
+
return Puri["_tsRank"]("ts_rank_cd", column, query, options);
|
|
405
420
|
}
|
|
406
421
|
|
|
407
422
|
static toTsVector(column: string, config: string = "simple"): SqlExpression<"tsvector"> {
|
|
@@ -434,12 +449,12 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
434
449
|
params.push(...weights);
|
|
435
450
|
}
|
|
436
451
|
|
|
437
|
-
if (
|
|
452
|
+
if (isStringValue(column)) {
|
|
438
453
|
sqlTemplate += `??, ${parser}(?, ?)`;
|
|
439
454
|
params.push(column, config, query);
|
|
440
455
|
} else {
|
|
441
|
-
sqlTemplate += `${column
|
|
442
|
-
params.push(...column
|
|
456
|
+
sqlTemplate += `${column["_sql"]}, ${parser}(?, ?)`;
|
|
457
|
+
params.push(...column["_params"], config, query);
|
|
443
458
|
}
|
|
444
459
|
|
|
445
460
|
if (normalization) {
|
|
@@ -483,7 +498,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
483
498
|
const queryClause = `ARRAY[${queryArr.map(() => "?").join(", ")}]`;
|
|
484
499
|
|
|
485
500
|
// 단일 컬럼인 경우
|
|
486
|
-
if (
|
|
501
|
+
if (isStringValue(columnOrColumns)) {
|
|
487
502
|
return Puri.rawString(`pgroonga_highlight_html(??, ${queryClause})`, [
|
|
488
503
|
columnOrColumns,
|
|
489
504
|
...queryArr,
|
|
@@ -507,13 +522,14 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
507
522
|
const selectClauses: (string | Knex.Raw)[] = [];
|
|
508
523
|
|
|
509
524
|
for (const [alias, columnOrFunction] of Object.entries(flatSelect)) {
|
|
510
|
-
if (
|
|
525
|
+
if (isSqlExpression(columnOrFunction)) {
|
|
511
526
|
// SQL 함수인 경우
|
|
512
527
|
selectClauses.push(
|
|
513
|
-
this.knex.raw(`${columnOrFunction
|
|
528
|
+
this.knex.raw(`${columnOrFunction["_sql"]} AS "${alias}"`, columnOrFunction["_params"]),
|
|
514
529
|
);
|
|
515
530
|
} else {
|
|
516
531
|
// 일반 컬럼인 경우
|
|
532
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
517
533
|
const columnPath = columnOrFunction as string;
|
|
518
534
|
if (alias === columnPath) {
|
|
519
535
|
// alias와 컬럼명이 같으면 alias 생략
|
|
@@ -526,6 +542,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
526
542
|
}
|
|
527
543
|
|
|
528
544
|
this.knexQuery.select(selectClauses);
|
|
545
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
529
546
|
return this as any;
|
|
530
547
|
}
|
|
531
548
|
|
|
@@ -534,23 +551,23 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
534
551
|
* 예: { parent: { id: "parent.id", name: "parent.name" } }
|
|
535
552
|
* → { parent__id: "parent.id", parent__name: "parent.name" }
|
|
536
553
|
*/
|
|
537
|
-
private
|
|
538
|
-
|
|
539
|
-
|
|
554
|
+
private *flattenSelectEntries(
|
|
555
|
+
selectObj: SelectObject<TTables>,
|
|
556
|
+
prefix = "",
|
|
557
|
+
): Generator<[string, SelectValue<TTables>], void> {
|
|
540
558
|
for (const [key, value] of Object.entries(selectObj)) {
|
|
541
559
|
const fullKey = prefix ? `${prefix}__${key}` : key;
|
|
542
560
|
|
|
543
|
-
if (
|
|
544
|
-
|
|
545
|
-
const nested = this.flattenSelect(value, fullKey);
|
|
546
|
-
Object.assign(flatSelect, nested);
|
|
561
|
+
if (isNestedSelectObject(value)) {
|
|
562
|
+
yield* this.flattenSelectEntries(value, fullKey);
|
|
547
563
|
} else {
|
|
548
|
-
|
|
549
|
-
flatSelect[fullKey] = value;
|
|
564
|
+
yield [fullKey, value];
|
|
550
565
|
}
|
|
551
566
|
}
|
|
567
|
+
}
|
|
552
568
|
|
|
553
|
-
|
|
569
|
+
private flattenSelect(selectObj: SelectObject<TTables>, prefix = "") {
|
|
570
|
+
return Object.fromEntries(this.flattenSelectEntries(selectObj, prefix));
|
|
554
571
|
}
|
|
555
572
|
|
|
556
573
|
// SELECT (select는 overwrite, appendSelect는 append)
|
|
@@ -563,11 +580,12 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
563
580
|
const selectClauses: (string | Knex.Raw)[] = [];
|
|
564
581
|
|
|
565
582
|
for (const [alias, columnOrFunction] of Object.entries(flatSelect)) {
|
|
566
|
-
if (
|
|
583
|
+
if (isSqlExpression(columnOrFunction)) {
|
|
567
584
|
selectClauses.push(
|
|
568
|
-
this.knex.raw(`${columnOrFunction
|
|
585
|
+
this.knex.raw(`${columnOrFunction["_sql"]} AS ${alias}`, columnOrFunction["_params"]),
|
|
569
586
|
);
|
|
570
587
|
} else {
|
|
588
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
571
589
|
const columnPath = columnOrFunction as string;
|
|
572
590
|
if (alias === columnPath) {
|
|
573
591
|
selectClauses.push(columnPath);
|
|
@@ -578,12 +596,14 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
578
596
|
}
|
|
579
597
|
|
|
580
598
|
this.knexQuery.select(selectClauses);
|
|
599
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
581
600
|
return this as any;
|
|
582
601
|
}
|
|
583
602
|
|
|
584
603
|
// SELECT *
|
|
585
604
|
selectAll(): Puri<TSchema, TTables, SelectAllResult<TTables>> {
|
|
586
605
|
this.knexQuery.select("*");
|
|
606
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
587
607
|
return this as any;
|
|
588
608
|
}
|
|
589
609
|
|
|
@@ -606,15 +626,18 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
606
626
|
// knex에 없어서 직접 구현함
|
|
607
627
|
clearJoin(alias: string): this {
|
|
608
628
|
let removed = false;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
629
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
630
|
+
(this.knexQuery as any)["_statements"] = (this.knexQuery as any)["_statements"].filter(
|
|
631
|
+
(s: any) => {
|
|
632
|
+
if ("joinType" in s) {
|
|
633
|
+
const shouldRemove = this.getKnexJoinAlias(s.table) === alias;
|
|
634
|
+
removed ||= shouldRemove;
|
|
635
|
+
return !shouldRemove;
|
|
636
|
+
} else {
|
|
637
|
+
return true;
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
);
|
|
618
641
|
if (removed && this.correlationRegistry.get(alias)?.kind === "join") {
|
|
619
642
|
this.correlationRegistry.delete(alias);
|
|
620
643
|
}
|
|
@@ -668,7 +691,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
668
691
|
): Puri<TSchema, TTables & Record<TJoinTable, TSchema[TJoinTable]>, TResult>;
|
|
669
692
|
// JOIN 실제 구현
|
|
670
693
|
join(tableNameOrSpec: any, ...args: any[]): any {
|
|
671
|
-
return this
|
|
694
|
+
return this["__commonJoin"]("join", tableNameOrSpec, ...args);
|
|
672
695
|
}
|
|
673
696
|
|
|
674
697
|
// ENSURE JOIN: 테이블 + Alias
|
|
@@ -684,7 +707,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
684
707
|
right: `${TJoinTable & string}.${ColumnKeys<TSchema[TJoinTable]>}`,
|
|
685
708
|
): Puri<TSchema, TTables & Record<TJoinTable, TSchema[TJoinTable]>, TResult>;
|
|
686
709
|
ensureJoin(tableNameOrSpec: any, left: string, right: string): any {
|
|
687
|
-
return this
|
|
710
|
+
return this["__ensureJoin"]("join", tableNameOrSpec, left, right);
|
|
688
711
|
}
|
|
689
712
|
|
|
690
713
|
// LEFT JOIN: 서브쿼리 + Alias
|
|
@@ -735,7 +758,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
735
758
|
): Puri<TSchema, TTables & Record<TJoinTable, TSchema[TJoinTable] & LeftJoinedMarker>, TResult>;
|
|
736
759
|
// LEFT JOIN 실제 구현
|
|
737
760
|
leftJoin(tableNameOrSpec: any, ...args: any[]): any {
|
|
738
|
-
return this
|
|
761
|
+
return this["__commonJoin"]("leftJoin", tableNameOrSpec, ...args);
|
|
739
762
|
}
|
|
740
763
|
|
|
741
764
|
// ENSURE LEFT JOIN: 테이블 + Alias
|
|
@@ -763,18 +786,18 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
763
786
|
TResult
|
|
764
787
|
>;
|
|
765
788
|
ensureLeftJoin(tableNameOrSpec: any, left: string, right: string): any {
|
|
766
|
-
return this
|
|
789
|
+
return this["__ensureJoin"]("leftJoin", tableNameOrSpec, left, right);
|
|
767
790
|
}
|
|
768
791
|
|
|
769
792
|
__commonJoin(joinType: "join" | "leftJoin", tableNameOrSpec: any, ...args: any[]): this {
|
|
770
793
|
const registration = this.createJoinRegistration(joinType, tableNameOrSpec, args);
|
|
771
794
|
this.assertCorrelationAvailable(registration);
|
|
772
795
|
|
|
773
|
-
if (
|
|
796
|
+
if (isStringValue(tableNameOrSpec)) {
|
|
774
797
|
// Case 1: join("posts", ...)
|
|
775
798
|
const tableName = tableNameOrSpec;
|
|
776
799
|
|
|
777
|
-
if (args.length === 1 &&
|
|
800
|
+
if (args.length === 1 && isFunctionValue(args[0])) {
|
|
778
801
|
// join("posts", callback)
|
|
779
802
|
const callback = args[0];
|
|
780
803
|
this.knexQuery[joinType](tableName, (joinClause) => {
|
|
@@ -785,7 +808,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
785
808
|
const [left, right] = args;
|
|
786
809
|
this.knexQuery[joinType](tableName, left, right);
|
|
787
810
|
}
|
|
788
|
-
} else if (
|
|
811
|
+
} else if (isObjectValue(tableNameOrSpec)) {
|
|
789
812
|
// Case 2: join({ alias: "table" }, ...) or join({ alias: subquery }, ...)
|
|
790
813
|
const entries = Object.entries(tableNameOrSpec);
|
|
791
814
|
if (entries.length !== 1) {
|
|
@@ -794,9 +817,9 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
794
817
|
assert(entries[0]);
|
|
795
818
|
const [[alias, spec]] = entries;
|
|
796
819
|
|
|
797
|
-
if (
|
|
820
|
+
if (isStringValue(spec)) {
|
|
798
821
|
// 테이블: join({ p: "posts" }, ...)
|
|
799
|
-
if (args.length === 1 &&
|
|
822
|
+
if (args.length === 1 && isFunctionValue(args[0])) {
|
|
800
823
|
// Callback
|
|
801
824
|
const callback = args[0];
|
|
802
825
|
this.knexQuery[joinType]({ [alias]: spec }, (joinClause) => {
|
|
@@ -809,7 +832,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
809
832
|
}
|
|
810
833
|
} else if (spec instanceof Puri) {
|
|
811
834
|
// 서브쿼리: join({ sq: subquery }, ...)
|
|
812
|
-
if (args.length === 1 &&
|
|
835
|
+
if (args.length === 1 && isFunctionValue(args[0])) {
|
|
813
836
|
// Callback
|
|
814
837
|
const callback = args[0];
|
|
815
838
|
this.knexQuery[joinType](spec.rawQuery().as(alias), (joinClause) => {
|
|
@@ -846,7 +869,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
846
869
|
const existing = this.correlationRegistry.get(requested.alias);
|
|
847
870
|
|
|
848
871
|
if (!existing) {
|
|
849
|
-
return this
|
|
872
|
+
return this["__commonJoin"](joinType, tableNameOrSpec, left, right);
|
|
850
873
|
}
|
|
851
874
|
|
|
852
875
|
if (this.isSameJoinRegistration(existing, requested)) {
|
|
@@ -864,10 +887,10 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
864
887
|
let alias: string;
|
|
865
888
|
let table: string | null;
|
|
866
889
|
|
|
867
|
-
if (
|
|
890
|
+
if (isStringValue(tableNameOrSpec)) {
|
|
868
891
|
alias = tableNameOrSpec;
|
|
869
892
|
table = tableNameOrSpec;
|
|
870
|
-
} else if (
|
|
893
|
+
} else if (isObjectValue(tableNameOrSpec)) {
|
|
871
894
|
const entries = Object.entries(tableNameOrSpec);
|
|
872
895
|
if (entries.length !== 1) {
|
|
873
896
|
throw new Error("Table spec must have exactly one entry");
|
|
@@ -875,14 +898,14 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
875
898
|
assert(entries[0]);
|
|
876
899
|
const [[joinAlias, spec]] = entries;
|
|
877
900
|
alias = joinAlias;
|
|
878
|
-
table =
|
|
901
|
+
table = isStringValue(spec) ? spec : null;
|
|
879
902
|
} else {
|
|
880
903
|
throw new Error("Invalid arguments");
|
|
881
904
|
}
|
|
882
905
|
|
|
883
906
|
const [left, right] = args;
|
|
884
907
|
const reusable =
|
|
885
|
-
table !== null && args.length === 2 &&
|
|
908
|
+
table !== null && args.length === 2 && isStringValue(left) && isStringValue(right);
|
|
886
909
|
|
|
887
910
|
return {
|
|
888
911
|
kind: "join",
|
|
@@ -956,19 +979,19 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
956
979
|
}
|
|
957
980
|
}
|
|
958
981
|
|
|
959
|
-
private getKnexJoinAlias(table:
|
|
960
|
-
if (
|
|
982
|
+
private getKnexJoinAlias<Value>(table: Value): string | null {
|
|
983
|
+
if (isStringValue(table)) {
|
|
961
984
|
return table;
|
|
962
985
|
}
|
|
963
|
-
if (
|
|
986
|
+
if (isObjectValue(table) && table !== null) {
|
|
964
987
|
if (
|
|
965
988
|
"_single" in table &&
|
|
966
|
-
|
|
967
|
-
table
|
|
968
|
-
"as" in table
|
|
969
|
-
|
|
989
|
+
isObjectValue(table["_single"]) &&
|
|
990
|
+
table["_single"] !== null &&
|
|
991
|
+
"as" in table["_single"] &&
|
|
992
|
+
isStringValue(table["_single"].as)
|
|
970
993
|
) {
|
|
971
|
-
return table
|
|
994
|
+
return table["_single"].as;
|
|
972
995
|
}
|
|
973
996
|
return Object.keys(table)[0] ?? null;
|
|
974
997
|
}
|
|
@@ -993,15 +1016,15 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
993
1016
|
// WHERE: 컬럼 - 사용: .where("u.id", "like", "%test%")
|
|
994
1017
|
where(...args: [columnOrConditions: any, operatorOrValue?: any, value?: any]): this {
|
|
995
1018
|
const [columnOrConditions, operatorOrValue, value] = args;
|
|
996
|
-
if (
|
|
1019
|
+
if (isObjectValue(columnOrConditions)) {
|
|
997
1020
|
this.knexQuery.where(columnOrConditions);
|
|
998
|
-
} else if (
|
|
1021
|
+
} else if (value === undefined) {
|
|
999
1022
|
if (operatorOrValue === null) {
|
|
1000
1023
|
this.knexQuery.whereNull(columnOrConditions);
|
|
1001
1024
|
return this;
|
|
1002
1025
|
}
|
|
1003
1026
|
this.knexQuery.where(columnOrConditions, operatorOrValue);
|
|
1004
|
-
} else if (
|
|
1027
|
+
} else if (value !== undefined) {
|
|
1005
1028
|
if (value === null) {
|
|
1006
1029
|
if (operatorOrValue === "!=") {
|
|
1007
1030
|
this.knexQuery.whereNotNull(columnOrConditions);
|
|
@@ -1021,18 +1044,32 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1021
1044
|
// WHERE IN
|
|
1022
1045
|
whereIn<TColumn extends AvailableColumns<TTables>>(
|
|
1023
1046
|
column: TColumn,
|
|
1024
|
-
values: ExtractColumnType<TTables, TColumn & string>[],
|
|
1047
|
+
values: (ExtractColumnType<TTables, TColumn & string> & Knex.Value)[],
|
|
1025
1048
|
): Puri<TSchema, TTables, TResult> {
|
|
1026
|
-
|
|
1049
|
+
// Knex의 비어 있는 IN 배열 처리와 동일하게 항상 거짓인 조건을 생성합니다.
|
|
1050
|
+
if (values.length === 0) {
|
|
1051
|
+
this.knexQuery.whereRaw("1 = 0");
|
|
1052
|
+
} else {
|
|
1053
|
+
const placeholders = values.map(() => "?").join(", ");
|
|
1054
|
+
this.knexQuery.whereRaw(`?? in (${placeholders})`, [String(column), ...values]);
|
|
1055
|
+
}
|
|
1056
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1027
1057
|
return this as any;
|
|
1028
1058
|
}
|
|
1029
1059
|
|
|
1030
1060
|
// WHERE NOT IN
|
|
1031
1061
|
whereNotIn<TColumn extends AvailableColumns<TTables>>(
|
|
1032
1062
|
column: TColumn,
|
|
1033
|
-
values: ExtractColumnType<TTables, TColumn & string>[],
|
|
1063
|
+
values: (ExtractColumnType<TTables, TColumn & string> & Knex.Value)[],
|
|
1034
1064
|
): Puri<TSchema, TTables, TResult> {
|
|
1035
|
-
|
|
1065
|
+
// Knex의 비어 있는 NOT IN 배열 처리와 동일하게 항상 참인 조건을 생성합니다.
|
|
1066
|
+
if (values.length === 0) {
|
|
1067
|
+
this.knexQuery.whereRaw("1 = 1");
|
|
1068
|
+
} else {
|
|
1069
|
+
const placeholders = values.map(() => "?").join(", ");
|
|
1070
|
+
this.knexQuery.whereRaw(`?? not in (${placeholders})`, [String(column), ...values]);
|
|
1071
|
+
}
|
|
1072
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1036
1073
|
return this as any;
|
|
1037
1074
|
}
|
|
1038
1075
|
|
|
@@ -1090,13 +1127,14 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1090
1127
|
options?: TsQueryOptions | TsQueryConfig,
|
|
1091
1128
|
): this {
|
|
1092
1129
|
const opts =
|
|
1093
|
-
|
|
1130
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1131
|
+
isStringValue(options) ? ({ config: options } as TsQueryOptions) : (options ?? {});
|
|
1094
1132
|
|
|
1095
1133
|
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
1096
1134
|
const config = opts.config ?? "simple";
|
|
1097
1135
|
const columnExpr =
|
|
1098
|
-
|
|
1099
|
-
? column
|
|
1136
|
+
isSqlExpression(column) && column["_type"] === "sql_expression"
|
|
1137
|
+
? column["_sql"]
|
|
1100
1138
|
: String(column);
|
|
1101
1139
|
|
|
1102
1140
|
this.knexQuery.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, value]);
|
|
@@ -1110,19 +1148,19 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1110
1148
|
operator?: FuzzyOperator;
|
|
1111
1149
|
},
|
|
1112
1150
|
): this {
|
|
1113
|
-
const operator =
|
|
1151
|
+
const operator = parseFuzzyOperator(options?.operator);
|
|
1114
1152
|
|
|
1115
1153
|
if (operator === "%") {
|
|
1116
|
-
if (
|
|
1117
|
-
this.knexQuery.whereRaw(`${column
|
|
1154
|
+
if (isSqlExpression(column)) {
|
|
1155
|
+
this.knexQuery.whereRaw(`${column["_sql"]} ${operator} ?`, [...column["_params"], value]);
|
|
1118
1156
|
} else {
|
|
1119
1157
|
this.knexQuery.whereRaw(`?? ${operator} ?`, [column, value]);
|
|
1120
1158
|
}
|
|
1121
1159
|
return this;
|
|
1122
1160
|
}
|
|
1123
1161
|
|
|
1124
|
-
if (
|
|
1125
|
-
this.knexQuery.whereRaw(`? ${operator} ${column
|
|
1162
|
+
if (isSqlExpression(column)) {
|
|
1163
|
+
this.knexQuery.whereRaw(`? ${operator} ${column["_sql"]}`, [value, ...column["_params"]]);
|
|
1126
1164
|
} else {
|
|
1127
1165
|
this.knexQuery.whereRaw(`? ${operator} ??`, [value, column]);
|
|
1128
1166
|
}
|
|
@@ -1167,7 +1205,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1167
1205
|
): this {
|
|
1168
1206
|
if (isOrderByEntries(columnOrColumns)) {
|
|
1169
1207
|
for (const entry of columnOrColumns) {
|
|
1170
|
-
if (
|
|
1208
|
+
if (isStringValue(entry) || isSqlExpression(entry)) {
|
|
1171
1209
|
this.applyOrderBy(entry);
|
|
1172
1210
|
} else {
|
|
1173
1211
|
this.applyOrderBy(entry.column, entry.order, entry.nulls);
|
|
@@ -1188,10 +1226,10 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1188
1226
|
const normalizedDirection = normalizeOrderByDirection(direction);
|
|
1189
1227
|
const normalizedNulls = normalizeOrderByNulls(nulls);
|
|
1190
1228
|
|
|
1191
|
-
if (
|
|
1229
|
+
if (isSqlExpression(column)) {
|
|
1192
1230
|
this.knexQuery.orderByRaw(
|
|
1193
|
-
`${column
|
|
1194
|
-
column
|
|
1231
|
+
`${column["_sql"]} ${normalizedDirection}${formatNullsSuffix(normalizedNulls)}`,
|
|
1232
|
+
column["_params"],
|
|
1195
1233
|
);
|
|
1196
1234
|
} else {
|
|
1197
1235
|
this.knexQuery.orderBy(column, normalizedDirection, normalizedNulls);
|
|
@@ -1281,7 +1319,8 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1281
1319
|
this.knexQuery.clear("order");
|
|
1282
1320
|
if (distinctOn) {
|
|
1283
1321
|
// DISTINCT ON은 SELECT 절의 맨 앞에 와야 하므로, 기존 select(subset 필드들)를 보존 후 clear하고 다시 추가
|
|
1284
|
-
|
|
1322
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1323
|
+
const existingSubsetCols = (this.knexQuery as any)["_statements"]
|
|
1285
1324
|
.filter((s: any) => s.grouping === "columns")
|
|
1286
1325
|
.flatMap((s: any) => s.value);
|
|
1287
1326
|
this.knexQuery.clear("select");
|
|
@@ -1304,7 +1343,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1304
1343
|
}
|
|
1305
1344
|
|
|
1306
1345
|
// threshold
|
|
1307
|
-
if (
|
|
1346
|
+
if (isNumberValue(threshold)) {
|
|
1308
1347
|
if (!Number.isFinite(threshold)) {
|
|
1309
1348
|
throw new Error(`Invalid vectorSimilarity threshold: ${threshold}`);
|
|
1310
1349
|
}
|
|
@@ -1323,6 +1362,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1323
1362
|
}
|
|
1324
1363
|
}
|
|
1325
1364
|
|
|
1365
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1326
1366
|
return this as any;
|
|
1327
1367
|
}
|
|
1328
1368
|
|
|
@@ -1381,6 +1421,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1381
1421
|
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,
|
|
1382
1422
|
): Promise<TResult1 | TResult2> {
|
|
1383
1423
|
Naite.t("puri:executed-query", this.toQuery());
|
|
1424
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1384
1425
|
return this.knexQuery.then(onfulfilled as any, onrejected);
|
|
1385
1426
|
}
|
|
1386
1427
|
catch<TResult2 = never>(
|
|
@@ -1407,6 +1448,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1407
1448
|
: ExtractColumnType<TTables, TColumn & string>[],
|
|
1408
1449
|
never
|
|
1409
1450
|
> {
|
|
1451
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1410
1452
|
this.knexQuery.pluck(column as string);
|
|
1411
1453
|
return new ResolvedPuri(this.knexQuery, this.knex, this.tableSpec);
|
|
1412
1454
|
}
|
|
@@ -1442,9 +1484,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1442
1484
|
* object 또는 object 배열을 받고, JSON 컬럼이 있으면 직렬화하여 반환합니다.
|
|
1443
1485
|
* 직접 값을 변경하므로 side effect가 있습니다.
|
|
1444
1486
|
*/
|
|
1445
|
-
private refineJsonColumns(
|
|
1446
|
-
data: Record<string, unknown> | Record<string, unknown>[],
|
|
1447
|
-
): typeof data {
|
|
1487
|
+
private refineJsonColumns<Row extends object>(data: Row | Row[]): typeof data {
|
|
1448
1488
|
// tableSpec이나 jsonColumns 없는 경우 바로 반환
|
|
1449
1489
|
if (!this.tableSpec || !this.tableSpec.jsonColumns.length) {
|
|
1450
1490
|
return data;
|
|
@@ -1455,17 +1495,21 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1455
1495
|
if (Array.isArray(data)) {
|
|
1456
1496
|
for (const item of data) {
|
|
1457
1497
|
for (const column of jsonColumns) {
|
|
1458
|
-
const value = item[column];
|
|
1498
|
+
const value = Object.entries(item).find(([key]) => key === column)?.[1];
|
|
1459
1499
|
if (value !== undefined && value !== null) {
|
|
1460
|
-
item
|
|
1500
|
+
Object.assign(item, {
|
|
1501
|
+
[column]: serializeJsonColumnValue(this.tableSpec, column, value),
|
|
1502
|
+
});
|
|
1461
1503
|
}
|
|
1462
1504
|
}
|
|
1463
1505
|
}
|
|
1464
1506
|
} else {
|
|
1465
1507
|
for (const column of jsonColumns) {
|
|
1466
|
-
const value = data[column];
|
|
1508
|
+
const value = Object.entries(data).find(([key]) => key === column)?.[1];
|
|
1467
1509
|
if (value !== undefined && value !== null) {
|
|
1468
|
-
data
|
|
1510
|
+
Object.assign(data, {
|
|
1511
|
+
[column]: serializeJsonColumnValue(this.tableSpec, column, value),
|
|
1512
|
+
});
|
|
1469
1513
|
}
|
|
1470
1514
|
}
|
|
1471
1515
|
}
|
|
@@ -1639,7 +1683,7 @@ export class Puri<TSchema, TTables extends Record<string, any>, TResult> {
|
|
|
1639
1683
|
}
|
|
1640
1684
|
}
|
|
1641
1685
|
|
|
1642
|
-
export class WhereGroup<TTables extends
|
|
1686
|
+
export class WhereGroup<TTables extends object> {
|
|
1643
1687
|
constructor(private builder: Knex.QueryBuilder) {}
|
|
1644
1688
|
|
|
1645
1689
|
// where 메서드들
|
|
@@ -1661,7 +1705,7 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1661
1705
|
// whereIn / whereNotIn 메서드들
|
|
1662
1706
|
whereIn<TColumn extends AvailableColumns<TTables>>(
|
|
1663
1707
|
column: TColumn,
|
|
1664
|
-
values: ExtractColumnType<TTables, TColumn & string>[],
|
|
1708
|
+
values: (ExtractColumnType<TTables, TColumn & string> & Knex.Value)[],
|
|
1665
1709
|
): this;
|
|
1666
1710
|
whereIn(...args: any[]): WhereGroup<TTables> {
|
|
1667
1711
|
this.builder.whereIn(args[0], args[1]);
|
|
@@ -1670,7 +1714,7 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1670
1714
|
|
|
1671
1715
|
whereNotIn<TColumn extends AvailableColumns<TTables>>(
|
|
1672
1716
|
column: TColumn,
|
|
1673
|
-
values: ExtractColumnType<TTables, TColumn & string>[],
|
|
1717
|
+
values: (ExtractColumnType<TTables, TColumn & string> & Knex.Value)[],
|
|
1674
1718
|
): this;
|
|
1675
1719
|
whereNotIn(...args: any[]): WhereGroup<TTables> {
|
|
1676
1720
|
this.builder.whereNotIn(args[0], args[1]);
|
|
@@ -1696,7 +1740,7 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1696
1740
|
// orWhereIn / orWhereNotIn 메서드들
|
|
1697
1741
|
orWhereIn<TColumn extends AvailableColumns<TTables>>(
|
|
1698
1742
|
column: TColumn,
|
|
1699
|
-
values: ExtractColumnType<TTables, TColumn & string>[],
|
|
1743
|
+
values: (ExtractColumnType<TTables, TColumn & string> & Knex.Value)[],
|
|
1700
1744
|
): this;
|
|
1701
1745
|
orWhereIn(...args: any[]): WhereGroup<TTables> {
|
|
1702
1746
|
this.builder.orWhereIn(args[0], args[1]);
|
|
@@ -1705,7 +1749,7 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1705
1749
|
|
|
1706
1750
|
orWhereNotIn<TColumn extends AvailableColumns<TTables>>(
|
|
1707
1751
|
column: TColumn,
|
|
1708
|
-
values: ExtractColumnType<TTables, TColumn & string>[],
|
|
1752
|
+
values: (ExtractColumnType<TTables, TColumn & string> & Knex.Value)[],
|
|
1709
1753
|
): this;
|
|
1710
1754
|
orWhereNotIn(...args: any[]): WhereGroup<TTables> {
|
|
1711
1755
|
this.builder.orWhereNotIn(args[0], args[1]);
|
|
@@ -1787,14 +1831,12 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1787
1831
|
): this;
|
|
1788
1832
|
whereTsSearch(...args: any[]): this {
|
|
1789
1833
|
const opts =
|
|
1790
|
-
|
|
1834
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1835
|
+
isStringValue(args[2]) ? ({ config: args[2] } as TsQueryOptions) : (args[2] ?? {});
|
|
1791
1836
|
|
|
1792
1837
|
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
1793
1838
|
const config = opts.config ?? "simple";
|
|
1794
|
-
const columnExpr =
|
|
1795
|
-
typeof args[0] === "object" && args[0]._type === "sql_expression"
|
|
1796
|
-
? args[0]._sql
|
|
1797
|
-
: String(args[0]);
|
|
1839
|
+
const columnExpr = isSqlExpression(args[0]) ? args[0]["_sql"] : String(args[0]);
|
|
1798
1840
|
|
|
1799
1841
|
this.builder.whereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, args[1]]);
|
|
1800
1842
|
return this;
|
|
@@ -1807,14 +1849,12 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1807
1849
|
): this;
|
|
1808
1850
|
orWhereTsSearch(...args: any[]): this {
|
|
1809
1851
|
const opts =
|
|
1810
|
-
|
|
1852
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1853
|
+
isStringValue(args[2]) ? ({ config: args[2] } as TsQueryOptions) : (args[2] ?? {});
|
|
1811
1854
|
|
|
1812
1855
|
const parser = opts.parser ?? "websearch_to_tsquery";
|
|
1813
1856
|
const config = opts.config ?? "simple";
|
|
1814
|
-
const columnExpr =
|
|
1815
|
-
typeof args[0] === "object" && args[0]._type === "sql_expression"
|
|
1816
|
-
? args[0]._sql
|
|
1817
|
-
: String(args[0]);
|
|
1857
|
+
const columnExpr = isSqlExpression(args[0]) ? args[0]["_sql"] : String(args[0]);
|
|
1818
1858
|
|
|
1819
1859
|
this.builder.orWhereRaw(`${columnExpr} @@ ${parser}(?, ?)`, [config, args[1]]);
|
|
1820
1860
|
return this;
|
|
@@ -1828,19 +1868,19 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1828
1868
|
},
|
|
1829
1869
|
): this;
|
|
1830
1870
|
whereFuzzy(...args: any[]): this {
|
|
1831
|
-
const operator =
|
|
1871
|
+
const operator = parseFuzzyOperator(args[2]?.operator);
|
|
1832
1872
|
|
|
1833
1873
|
if (operator === "%") {
|
|
1834
|
-
if (
|
|
1835
|
-
this.builder.whereRaw(`${args[0]
|
|
1874
|
+
if (isSqlExpression(args[0])) {
|
|
1875
|
+
this.builder.whereRaw(`${args[0]["_sql"]} ${operator} ?`, [...args[0]["_params"], args[1]]);
|
|
1836
1876
|
} else {
|
|
1837
1877
|
this.builder.whereRaw(`?? ${operator} ?`, [args[0], args[1]]);
|
|
1838
1878
|
}
|
|
1839
1879
|
return this;
|
|
1840
1880
|
}
|
|
1841
1881
|
|
|
1842
|
-
if (
|
|
1843
|
-
this.builder.whereRaw(`? ${operator} ${args[0]
|
|
1882
|
+
if (isSqlExpression(args[0])) {
|
|
1883
|
+
this.builder.whereRaw(`? ${operator} ${args[0]["_sql"]}`, [args[1], ...args[0]["_params"]]);
|
|
1844
1884
|
} else {
|
|
1845
1885
|
this.builder.whereRaw(`? ${operator} ??`, [args[1], args[0]]);
|
|
1846
1886
|
}
|
|
@@ -1855,19 +1895,22 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1855
1895
|
},
|
|
1856
1896
|
): this;
|
|
1857
1897
|
orWhereFuzzy(...args: any[]): this {
|
|
1858
|
-
const operator =
|
|
1898
|
+
const operator = parseFuzzyOperator(args[2]?.operator);
|
|
1859
1899
|
|
|
1860
1900
|
if (operator === "%") {
|
|
1861
|
-
if (
|
|
1862
|
-
this.builder.orWhereRaw(`${args[0]
|
|
1901
|
+
if (isSqlExpression(args[0])) {
|
|
1902
|
+
this.builder.orWhereRaw(`${args[0]["_sql"]} ${operator} ?`, [
|
|
1903
|
+
...args[0]["_params"],
|
|
1904
|
+
args[1],
|
|
1905
|
+
]);
|
|
1863
1906
|
} else {
|
|
1864
1907
|
this.builder.orWhereRaw(`?? ${operator} ?`, [args[0], args[1]]);
|
|
1865
1908
|
}
|
|
1866
1909
|
return this;
|
|
1867
1910
|
}
|
|
1868
1911
|
|
|
1869
|
-
if (
|
|
1870
|
-
this.builder.orWhereRaw(`? ${operator} ${args[0]
|
|
1912
|
+
if (isSqlExpression(args[0])) {
|
|
1913
|
+
this.builder.orWhereRaw(`? ${operator} ${args[0]["_sql"]}`, [args[1], ...args[0]["_params"]]);
|
|
1871
1914
|
} else {
|
|
1872
1915
|
this.builder.orWhereRaw(`? ${operator} ??`, [args[1], args[0]]);
|
|
1873
1916
|
}
|
|
@@ -1894,10 +1937,7 @@ export class WhereGroup<TTables extends Record<string, any>> {
|
|
|
1894
1937
|
}
|
|
1895
1938
|
|
|
1896
1939
|
// JOIN 절 그룹에는 Left와 Right에 대한 순서가 필요하지 않으므로, 모든 경우의 수를 계산해야함.
|
|
1897
|
-
export class JoinClauseGroup<
|
|
1898
|
-
TLeft extends Record<string, any>,
|
|
1899
|
-
TRight extends Record<string, any>,
|
|
1900
|
-
> {
|
|
1940
|
+
export class JoinClauseGroup<TLeft extends object, TRight extends object> {
|
|
1901
1941
|
constructor(private callback: Knex.JoinClause) {}
|
|
1902
1942
|
|
|
1903
1943
|
// ON(AND): 컬럼 = 컬럼
|
|
@@ -1939,6 +1979,7 @@ export class JoinClauseGroup<
|
|
|
1939
1979
|
on(callback: (nested: JoinClauseGroup<TRight, TLeft>) => void): this;
|
|
1940
1980
|
// ON(AND) 구현
|
|
1941
1981
|
on(...args: any[]): this {
|
|
1982
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1942
1983
|
this.callback.on(...(args as [string, string]));
|
|
1943
1984
|
return this;
|
|
1944
1985
|
}
|
|
@@ -1982,6 +2023,7 @@ export class JoinClauseGroup<
|
|
|
1982
2023
|
orOn(callback: (nested: JoinClauseGroup<TRight, TLeft>) => void): this;
|
|
1983
2024
|
// ON(OR) 구현
|
|
1984
2025
|
orOn(...args: any[]): this {
|
|
2026
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1985
2027
|
this.callback.orOn(...(args as [string, string]));
|
|
1986
2028
|
return this;
|
|
1987
2029
|
}
|
|
@@ -1992,6 +2034,7 @@ export class JoinClauseGroup<
|
|
|
1992
2034
|
onVal(column: AvailableColumns<TLeft>, operator: ComparisonOperator, value: any): this;
|
|
1993
2035
|
onVal(column: AvailableColumns<TRight>, operator: ComparisonOperator, value: any): this;
|
|
1994
2036
|
onVal(...args: any[]): this {
|
|
2037
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
1995
2038
|
(this.callback as any).onVal(...args);
|
|
1996
2039
|
return this;
|
|
1997
2040
|
}
|
|
@@ -2002,6 +2045,7 @@ export class JoinClauseGroup<
|
|
|
2002
2045
|
andOnVal(column: AvailableColumns<TLeft>, operator: ComparisonOperator, value: any): this;
|
|
2003
2046
|
andOnVal(column: AvailableColumns<TRight>, operator: ComparisonOperator, value: any): this;
|
|
2004
2047
|
andOnVal(...args: any[]): this {
|
|
2048
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
2005
2049
|
(this.callback as any).andOnVal(...args);
|
|
2006
2050
|
return this;
|
|
2007
2051
|
}
|
|
@@ -2012,6 +2056,7 @@ export class JoinClauseGroup<
|
|
|
2012
2056
|
orOnVal(column: AvailableColumns<TLeft>, operator: ComparisonOperator, value: any): this;
|
|
2013
2057
|
orOnVal(column: AvailableColumns<TRight>, operator: ComparisonOperator, value: any): this;
|
|
2014
2058
|
orOnVal(...args: any[]): this {
|
|
2059
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
2015
2060
|
(this.callback as any).orOnVal(...args);
|
|
2016
2061
|
return this;
|
|
2017
2062
|
}
|
|
@@ -2044,6 +2089,7 @@ export class ResolvedPuri<TResolved, TReturning> implements Promise<TResolved> {
|
|
|
2044
2089
|
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null,
|
|
2045
2090
|
): Promise<TResult1 | TResult2> {
|
|
2046
2091
|
Naite.t("puri:executed-query", this.toQuery());
|
|
2092
|
+
// SAFETY: 쿼리 빌더의 제네릭 계약과 선행 검증이 이 타입을 보장합니다.
|
|
2047
2093
|
return this.knexQuery.then(onfulfilled as any, onrejected);
|
|
2048
2094
|
}
|
|
2049
2095
|
|
|
@@ -2076,21 +2122,13 @@ export class ResolvedPuri<TResolved, TReturning> implements Promise<TResolved> {
|
|
|
2076
2122
|
this.knexQuery.onConflict(target).merge(update);
|
|
2077
2123
|
} else {
|
|
2078
2124
|
// action.update 객체 형태: { name: "John", count: raw(...) }
|
|
2079
|
-
const mergeObj
|
|
2125
|
+
const mergeObj = {};
|
|
2080
2126
|
|
|
2081
2127
|
for (const [key, value] of Object.entries(update)) {
|
|
2082
|
-
|
|
2083
|
-
value
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
value._type === "sql_expression"
|
|
2087
|
-
) {
|
|
2088
|
-
// SqlExpression → knex.raw()로 변환
|
|
2089
|
-
mergeObj[key] = this.knex.raw((value as SqlExpression<any>)._sql);
|
|
2090
|
-
} else {
|
|
2091
|
-
// 일반 값
|
|
2092
|
-
mergeObj[key] = serializeJsonColumnValue(this.tableSpec, key, value);
|
|
2093
|
-
}
|
|
2128
|
+
const mergedValue = isSqlExpression(value)
|
|
2129
|
+
? this.knex.raw(value["_sql"])
|
|
2130
|
+
: serializeJsonColumnValue(this.tableSpec, key, value);
|
|
2131
|
+
Object.assign(mergeObj, { [key]: mergedValue });
|
|
2094
2132
|
}
|
|
2095
2133
|
|
|
2096
2134
|
this.knexQuery.onConflict(target).merge(mergeObj);
|