@cosmicdrift/kumiko-framework 0.387.0 → 0.389.0
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/AGENTS.md +9 -1
- package/agents/examples/anonymous-access.md +1 -1
- package/agents/examples/apex-landing.md +204 -0
- package/agents/examples/api-worker-split.md +64 -0
- package/agents/examples/app-config.md +14 -0
- package/agents/examples/auth-mfa.md +115 -0
- package/agents/examples/env-composition.md +28 -1
- package/agents/examples/golden-path.md +13 -1
- package/agents/examples/legal-pages.md +1 -1
- package/agents/examples/lifecycle-hooks.md +55 -2
- package/agents/examples/list-table-options.md +466 -0
- package/agents/examples/pdf-audit-export.md +4 -2
- package/agents/examples/prod-boot-options.md +16 -0
- package/agents/examples/rate-limiting.md +48 -0
- package/agents/examples/record-detail-layout.md +692 -0
- package/agents/examples/seed-migration.md +212 -0
- package/agents/examples/state-machine.md +3 -2
- package/agents/examples/tenant-isolation.md +73 -1
- package/agents/examples/wizard-form.md +941 -0
- package/agents/examples/writeform-section.md +548 -0
- package/agents/examples.md +1 -0
- package/agents/features.md +19 -2
- package/agents/widgets.md +2 -0
- package/dist/api/api-constants.d.ts +1 -0
- package/dist/api/api-constants.js +2 -0
- package/dist/api/auth-routes-shared.d.ts +2 -0
- package/dist/api/auth-routes-shared.js +5 -0
- package/dist/api/client-error-route.js +10 -5
- package/dist/api/entity-read-access.d.ts +2 -1
- package/dist/api/entity-read-access.js +14 -0
- package/dist/api/export/export-cells-reference.d.ts +9 -0
- package/dist/api/export/export-cells-reference.js +21 -0
- package/dist/api/export/export-cells.d.ts +11 -0
- package/dist/api/export/export-cells.js +136 -0
- package/dist/api/export/export-ciphertext-guard.d.ts +2 -0
- package/dist/api/export/export-ciphertext-guard.js +27 -0
- package/dist/api/export/export-columns.d.ts +29 -0
- package/dist/api/export/export-columns.js +85 -0
- package/dist/api/export/export-errors.d.ts +4 -0
- package/dist/api/export/export-errors.js +14 -0
- package/dist/api/export/export-route.d.ts +4 -0
- package/dist/api/export/export-route.js +74 -0
- package/dist/api/export/export-rows.d.ts +13 -0
- package/dist/api/export/export-rows.js +62 -0
- package/dist/api/export/export-screen.d.ts +12 -0
- package/dist/api/export/export-screen.js +47 -0
- package/dist/api/export/export-xlsx-writer.d.ts +4 -0
- package/dist/api/export/export-xlsx-writer.js +21 -0
- package/dist/api/extra-route.d.ts +4 -0
- package/dist/api/index.d.ts +3 -1
- package/dist/api/index.js +3 -1
- package/dist/api/pii-leak-guard.d.ts +3 -0
- package/dist/api/pii-leak-guard.js +3 -2
- package/dist/api/request-context.d.ts +1 -1
- package/dist/api/request-context.js +1 -1
- package/dist/api/routes.d.ts +16 -0
- package/dist/api/routes.js +2 -2
- package/dist/api/server-boot-checks.d.ts +10 -0
- package/dist/api/server-boot-checks.js +157 -0
- package/dist/api/server-event-dispatcher.d.ts +26 -0
- package/dist/api/server-event-dispatcher.js +208 -0
- package/dist/api/server-extra-routes.d.ts +11 -0
- package/dist/api/server-extra-routes.js +206 -0
- package/dist/api/server-middleware.d.ts +20 -0
- package/dist/api/server-middleware.js +211 -0
- package/dist/api/server-routes.d.ts +19 -0
- package/dist/api/server-routes.js +299 -0
- package/dist/api/server-websocket-routes.d.ts +4 -0
- package/dist/api/server-websocket-routes.js +108 -0
- package/dist/api/server-wiring.d.ts +32 -0
- package/dist/api/server-wiring.js +238 -0
- package/dist/api/server.d.ts +10 -15
- package/dist/api/server.js +48 -1251
- package/dist/api/session-cookies.js +4 -4
- package/dist/api/sse-route.d.ts +2 -1
- package/dist/api/sse-route.js +27 -13
- package/dist/config/index.d.ts +3 -1
- package/dist/crypto/owner-transition-rekey.d.ts +5 -1
- package/dist/crypto/owner-transition-rekey.js +1 -1
- package/dist/crypto/pg-kms-adapter.d.ts +1 -0
- package/dist/crypto/pg-kms-adapter.js +12 -18
- package/dist/crypto/pii-field-encryption.d.ts +5 -1
- package/dist/crypto/pii-field-encryption.js +3 -1
- package/dist/db/aggregate-sql.d.ts +23 -0
- package/dist/db/aggregate-sql.js +165 -0
- package/dist/db/closed-connection.d.ts +9 -0
- package/dist/db/closed-connection.js +88 -0
- package/dist/db/connection.d.ts +4 -5
- package/dist/db/connection.js +29 -20
- package/dist/db/dialect.js +1 -1
- package/dist/db/distinct-on.d.ts +1 -1
- package/dist/db/driver-row-coercion.d.ts +2 -0
- package/dist/db/driver-row-coercion.js +186 -0
- package/dist/db/driver-value-preparation.d.ts +16 -0
- package/dist/db/driver-value-preparation.js +101 -0
- package/dist/db/entity-field-encryption.d.ts +1 -0
- package/dist/db/entity-field-encryption.js +1 -1
- package/dist/db/entity-table-meta.js +103 -110
- package/dist/db/event-store-executor-context.d.ts +2 -1
- package/dist/db/event-store-executor-read-aggregate-currencies.d.ts +17 -0
- package/dist/db/event-store-executor-read-aggregate-currencies.js +40 -0
- package/dist/db/event-store-executor-read-aggregate.d.ts +8 -0
- package/dist/db/event-store-executor-read-aggregate.js +143 -0
- package/dist/db/event-store-executor-read-filter.d.ts +31 -0
- package/dist/db/event-store-executor-read-filter.js +206 -0
- package/dist/db/event-store-executor-read-paging.d.ts +14 -0
- package/dist/db/event-store-executor-read-paging.js +99 -0
- package/dist/db/event-store-executor-read-rows.d.ts +6 -0
- package/dist/db/event-store-executor-read-rows.js +32 -0
- package/dist/db/event-store-executor-read-search.d.ts +28 -0
- package/dist/db/event-store-executor-read-search.js +221 -0
- package/dist/db/event-store-executor-read-sort.d.ts +41 -0
- package/dist/db/event-store-executor-read-sort.js +130 -0
- package/dist/db/event-store-executor-read-where.d.ts +24 -0
- package/dist/db/event-store-executor-read-where.js +81 -0
- package/dist/db/event-store-executor-read.d.ts +2 -9
- package/dist/db/event-store-executor-read.js +48 -701
- package/dist/db/event-store-executor-write-atomic.d.ts +4 -0
- package/dist/db/event-store-executor-write-atomic.js +41 -0
- package/dist/db/event-store-executor-write-steps.d.ts +17 -0
- package/dist/db/event-store-executor-write-steps.js +95 -0
- package/dist/db/event-store-executor-write.js +405 -509
- package/dist/db/event-store-executor.js +2 -1
- package/dist/db/executor-managed-tables.js +1 -1
- package/dist/db/index.d.ts +7 -3
- package/dist/db/index.js +6 -2
- package/dist/db/list-aggregate-labels.d.ts +14 -0
- package/dist/db/list-aggregate-labels.js +26 -0
- package/dist/db/migrate-generator.js +71 -86
- package/dist/db/migrate-runner.js +7 -4
- package/dist/db/pg-error.js +26 -21
- package/dist/db/queries/backfill-pii.js +3 -6
- package/dist/db/queries/database-now.js +2 -1
- package/dist/db/queries/shadow-swap.js +2 -3
- package/dist/db/query.d.ts +16 -15
- package/dist/db/query.js +76 -804
- package/dist/db/reference-data.js +19 -2
- package/dist/db/statement-timeout.js +2 -1
- package/dist/db/table-builder.js +113 -166
- package/dist/db/table-info.d.ts +10 -0
- package/dist/db/table-info.js +45 -0
- package/dist/db/temporal-value-guards.d.ts +6 -0
- package/dist/db/temporal-value-guards.js +15 -0
- package/dist/db/tenant-db-runner.d.ts +1 -0
- package/dist/db/tenant-db-runner.js +3 -0
- package/dist/db/tenant-db-upsert.d.ts +5 -0
- package/dist/db/tenant-db-upsert.js +91 -0
- package/dist/db/tenant-db.js +50 -10
- package/dist/db/where-clause.d.ts +6 -0
- package/dist/db/where-clause.js +236 -0
- package/dist/derivatives/delete-stored-file.js +2 -1
- package/dist/engine/boot-validator/boot-check.js +1 -1
- package/dist/engine/boot-validator/bundled-lists-table.d.ts +2 -0
- package/dist/engine/boot-validator/bundled-lists-table.js +36 -0
- package/dist/engine/boot-validator/detail-screens.js +2 -2
- package/dist/engine/boot-validator/entity-handler.d.ts +1 -0
- package/dist/engine/boot-validator/entity-handler.js +17 -0
- package/dist/engine/boot-validator/entity-list-aggregate-options.d.ts +3 -0
- package/dist/engine/boot-validator/entity-list-aggregate-options.js +23 -0
- package/dist/engine/boot-validator/form-derivations.js +35 -1
- package/dist/engine/boot-validator/i18n-keys.js +5 -3
- package/dist/engine/boot-validator/index.js +2 -0
- package/dist/engine/boot-validator/list-bulk-actions.d.ts +3 -0
- package/dist/engine/boot-validator/list-bulk-actions.js +49 -0
- package/dist/engine/boot-validator/list-column-layout.d.ts +8 -0
- package/dist/engine/boot-validator/list-column-layout.js +41 -0
- package/dist/engine/boot-validator/list-table-aggregate-options.d.ts +24 -0
- package/dist/engine/boot-validator/list-table-aggregate-options.js +145 -0
- package/dist/engine/boot-validator/list-table-aggregate-query.d.ts +10 -0
- package/dist/engine/boot-validator/list-table-aggregate-query.js +31 -0
- package/dist/engine/boot-validator/list-table-export-options.d.ts +1 -0
- package/dist/engine/boot-validator/list-table-export-options.js +27 -0
- package/dist/engine/boot-validator/list-table-options.d.ts +3 -0
- package/dist/engine/boot-validator/list-table-options.js +77 -0
- package/dist/engine/boot-validator/list-table-reject-unknown-keys.d.ts +1 -0
- package/dist/engine/boot-validator/list-table-reject-unknown-keys.js +7 -0
- package/dist/engine/boot-validator/pii-retention.js +233 -155
- package/dist/engine/boot-validator/projection-list-screens.d.ts +1 -1
- package/dist/engine/boot-validator/projection-list-screens.js +3 -13
- package/dist/engine/boot-validator/related-list-table-rules.d.ts +4 -0
- package/dist/engine/boot-validator/related-list-table-rules.js +42 -0
- package/dist/engine/boot-validator/screens-actions.d.ts +1 -0
- package/dist/engine/boot-validator/screens-actions.js +8 -1
- package/dist/engine/boot-validator/screens-dashboard.js +2 -5
- package/dist/engine/boot-validator/screens-forms.js +2 -6
- package/dist/engine/boot-validator/screens-kind-config-edit.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-config-edit.js +88 -0
- package/dist/engine/boot-validator/screens-kind-entity-edit.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-entity-edit.js +55 -0
- package/dist/engine/boot-validator/screens-kind-entity-list.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-entity-list.js +235 -0
- package/dist/engine/boot-validator/screens-kind-projection-detail.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-projection-detail.js +235 -0
- package/dist/engine/boot-validator/screens-kind-projection-list.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-projection-list.js +56 -0
- package/dist/engine/boot-validator/screens-kind-secret-mint.d.ts +3 -0
- package/dist/engine/boot-validator/screens-kind-secret-mint.js +28 -0
- package/dist/engine/boot-validator/screens-kind-shared.d.ts +37 -0
- package/dist/engine/boot-validator/screens-kind-shared.js +142 -0
- package/dist/engine/boot-validator/screens-lists.d.ts +2 -1
- package/dist/engine/boot-validator/screens-lists.js +24 -11
- package/dist/engine/boot-validator/screens.d.ts +0 -2
- package/dist/engine/boot-validator/screens.js +99 -860
- package/dist/engine/build-app-schema.d.ts +2 -1
- package/dist/engine/build-app-schema.js +65 -97
- package/dist/engine/build-config-feature-schema.js +6 -1
- package/dist/engine/define-feature.js +13 -2
- package/dist/engine/define-handler.js +1 -0
- package/dist/engine/entity-handlers.d.ts +13 -0
- package/dist/engine/entity-handlers.js +10 -21
- package/dist/engine/entity-list-runtime-options.d.ts +8 -0
- package/dist/engine/entity-list-runtime-options.js +18 -0
- package/dist/engine/feature-ast/extractors/handlers.js +1 -0
- package/dist/engine/feature-ast/extractors/index.d.ts +1 -1
- package/dist/engine/feature-ast/extractors/index.js +1 -1
- package/dist/engine/feature-ast/extractors/round1.d.ts +2 -1
- package/dist/engine/feature-ast/extractors/round1.js +6 -0
- package/dist/engine/feature-ast/extractors/round2.js +25 -6
- package/dist/engine/feature-ast/index.d.ts +1 -1
- package/dist/engine/feature-ast/parse.js +3 -1
- package/dist/engine/feature-ast/patch.d.ts +2 -0
- package/dist/engine/feature-ast/patch.js +5 -182
- package/dist/engine/feature-ast/pattern-change-schema.d.ts +10 -245
- package/dist/engine/feature-ast/pattern-change-schema.js +10 -163
- package/dist/engine/feature-ast/pattern-id-matchers.d.ts +7 -0
- package/dist/engine/feature-ast/pattern-id-matchers.js +211 -0
- package/dist/engine/feature-ast/pattern-id-schema.d.ts +251 -0
- package/dist/engine/feature-ast/pattern-id-schema.js +166 -0
- package/dist/engine/feature-ast/patterns.d.ts +14 -1
- package/dist/engine/feature-ast/patterns.js +44 -51
- package/dist/engine/feature-ast/render.js +52 -87
- package/dist/engine/feature-builder-state.d.ts +1 -0
- package/dist/engine/feature-builder-state.js +1 -0
- package/dist/engine/feature-entity-handlers.js +3 -0
- package/dist/engine/feature-manifest.d.ts +1 -0
- package/dist/engine/feature-manifest.js +1 -0
- package/dist/engine/field-access.d.ts +1 -0
- package/dist/engine/field-access.js +12 -0
- package/dist/engine/form-derivations.js +18 -7
- package/dist/engine/handler-field-references.js +1 -1
- package/dist/engine/index.d.ts +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/engine/pattern-library/library.js +2 -1
- package/dist/engine/pattern-library/static-schemas.d.ts +1 -0
- package/dist/engine/pattern-library/static-schemas.js +9 -0
- package/dist/engine/project-app-schema-for-roles.d.ts +2 -0
- package/dist/engine/project-app-schema-for-roles.js +6 -4
- package/dist/engine/registry-ingest.js +1 -1
- package/dist/engine/schema-builder.js +228 -212
- package/dist/engine/screen-filter-ops.js +2 -0
- package/dist/engine/screen-helpers.js +1 -1
- package/dist/engine/screen-kind.d.ts +7 -0
- package/dist/engine/screen-kind.js +1 -0
- package/dist/engine/strip-disabled-features-from-app-schema.js +58 -17
- package/dist/engine/types/feature.d.ts +1 -0
- package/dist/engine/types/index.d.ts +4 -3
- package/dist/engine/types/screen.d.ts +1 -1
- package/dist/engine/types/screen.js +1 -1
- package/dist/engine/validate-projection-allowlist.js +2 -1
- package/dist/entrypoint/index.d.ts +6 -1
- package/dist/entrypoint/index.js +10 -1
- package/dist/errors/docs-url.d.ts +1 -1
- package/dist/errors/docs-url.js +22 -2
- package/dist/es-ops/context.js +1 -1
- package/dist/event-store/admin-api.js +1 -1
- package/dist/event-store/event-store.d.ts +1 -0
- package/dist/event-store/event-store.js +17 -8
- package/dist/event-store/provenance-append.js +1 -1
- package/dist/files/bind-pending-file-refs.js +3 -3
- package/dist/files/create-file-ref-from-bytes.js +7 -1
- package/dist/files/create-file-ref.d.ts +3 -0
- package/dist/files/create-file-ref.js +11 -2
- package/dist/files/file-handle.js +2 -3
- package/dist/files/file-routes.d.ts +2 -0
- package/dist/files/file-routes.js +40 -10
- package/dist/files/provider-resolver.d.ts +1 -0
- package/dist/files/provider-resolver.js +1 -1
- package/dist/files/record-write-check.d.ts +6 -0
- package/dist/files/record-write-check.js +13 -0
- package/dist/files/resolve-content-type.js +43 -0
- package/dist/files/upload-ledger.d.ts +2 -2
- package/dist/files/upload-ledger.js +11 -4
- package/dist/i18n/required-surface-keys.js +189 -208
- package/dist/internal/stack-support.d.ts +2 -1
- package/dist/internal/stack-support.js +1 -1
- package/dist/internal/testing.js +1 -1
- package/dist/jobs/job-runner-context.d.ts +32 -0
- package/dist/jobs/job-runner-context.js +305 -0
- package/dist/jobs/job-runner-execution.d.ts +7 -0
- package/dist/jobs/job-runner-execution.js +160 -0
- package/dist/jobs/job-runner-gates.d.ts +19 -0
- package/dist/jobs/job-runner-gates.js +198 -0
- package/dist/jobs/job-runner-helpers.d.ts +17 -3
- package/dist/jobs/job-runner-helpers.js +61 -2
- package/dist/jobs/job-runner-scope.d.ts +44 -0
- package/dist/jobs/job-runner-scope.js +102 -0
- package/dist/jobs/job-runner-types.d.ts +12 -0
- package/dist/jobs/job-runner.d.ts +0 -1
- package/dist/jobs/job-runner.js +50 -657
- package/dist/observability/escape-hatch-report.d.ts +3 -0
- package/dist/observability/escape-hatch-report.js +21 -3
- package/dist/pipeline/after-rollback-sink.d.ts +6 -0
- package/dist/pipeline/after-rollback-sink.js +32 -0
- package/dist/pipeline/cascade-handler.js +165 -138
- package/dist/pipeline/dispatch-batch.js +8 -1
- package/dist/pipeline/dispatch-query.js +10 -3
- package/dist/pipeline/dispatch-shared.d.ts +13 -3
- package/dist/pipeline/dispatch-shared.js +62 -710
- package/dist/pipeline/dispatch-write.js +296 -189
- package/dist/pipeline/event-dispatcher-admin.js +2 -1
- package/dist/pipeline/event-dispatcher-delivery.js +6 -6
- package/dist/pipeline/event-dispatcher.d.ts +1 -0
- package/dist/pipeline/event-dispatcher.js +6 -9
- package/dist/pipeline/handler-context-auth.d.ts +9 -0
- package/dist/pipeline/handler-context-auth.js +54 -0
- package/dist/pipeline/handler-context-config.d.ts +14 -0
- package/dist/pipeline/handler-context-config.js +113 -0
- package/dist/pipeline/handler-context-db.d.ts +24 -0
- package/dist/pipeline/handler-context-db.js +149 -0
- package/dist/pipeline/handler-context-dispatch.d.ts +23 -0
- package/dist/pipeline/handler-context-dispatch.js +101 -0
- package/dist/pipeline/handler-context-events.d.ts +41 -0
- package/dist/pipeline/handler-context-events.js +239 -0
- package/dist/pipeline/handler-context-notify.d.ts +12 -0
- package/dist/pipeline/handler-context-notify.js +55 -0
- package/dist/pipeline/handler-context-observability.d.ts +7 -0
- package/dist/pipeline/handler-context-observability.js +21 -0
- package/dist/pipeline/handler-context-scope.d.ts +48 -0
- package/dist/pipeline/handler-context-scope.js +88 -0
- package/dist/pipeline/notify-scope.js +12 -1
- package/dist/pipeline/pre-handler-gates.js +20 -4
- package/dist/pipeline/pre-transaction-reservations.d.ts +1 -0
- package/dist/pipeline/pre-transaction-reservations.js +9 -3
- package/dist/pipeline/projection-rebuild.js +2 -1
- package/dist/pipeline/system-hooks.d.ts +3 -1
- package/dist/pipeline/system-hooks.js +55 -6
- package/dist/pipeline/write-result-masking.js +13 -10
- package/dist/schema-cli/apply-command.d.ts +2 -0
- package/dist/schema-cli/apply-command.js +97 -0
- package/dist/schema-cli/baseline-command.d.ts +2 -0
- package/dist/schema-cli/baseline-command.js +33 -0
- package/dist/schema-cli/generate-command.d.ts +2 -0
- package/dist/schema-cli/generate-command.js +90 -0
- package/dist/schema-cli/shared.d.ts +39 -0
- package/dist/schema-cli/shared.js +95 -0
- package/dist/schema-cli/status-command.d.ts +2 -0
- package/dist/schema-cli/status-command.js +73 -0
- package/dist/schema-cli/validate-boot-input.d.ts +5 -0
- package/dist/schema-cli/validate-boot-input.js +130 -0
- package/dist/schema-cli/validate-command.d.ts +2 -0
- package/dist/schema-cli/validate-command.js +130 -0
- package/dist/schema-cli.d.ts +2 -18
- package/dist/schema-cli.js +47 -604
- package/dist/search/meilisearch-adapter.js +2 -1
- package/dist/search/reindex-entity.js +15 -5
- package/dist/ui-types/index.d.ts +2 -2
- package/dist/ui-types/index.js +1 -1
- package/dist/upgrade-changelog.d.ts +2 -0
- package/dist/upgrade-changelog.js +14 -0
- package/dist/upgrade-cli.d.ts +3 -12
- package/dist/upgrade-cli.js +171 -197
- package/dist/upgrade-marker-parse.d.ts +32 -0
- package/dist/upgrade-marker-parse.js +73 -0
- package/package.json +9 -6
- package/src/changes.json +555 -0
- package/src/scripts/codemod/codemod-support.ts +1 -1
- package/src/scripts/codemod/db-factory.ts +1 -1
- package/src/scripts/codemod/feature-layout.ts +10 -2
- package/src/scripts/codemod/object-form.ts +41 -4
- package/src/scripts/codemod/package-merge.ts +58 -8
- package/src/scripts/codemod/pii-personal-migration.ts +175 -145
- package/src/scripts/codemod/testing-injection.ts +122 -42
- package/src/scripts/codemod/testing-move.ts +29 -7
- package/dist/engine/provider-plugin-context.d.ts +0 -3
- package/dist/engine/provider-plugin-context.js +0 -28
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { buildExecutorContext } from "./event-store-executor-context.js";
|
|
2
2
|
import { createReadVerbs } from "./event-store-executor-read.js";
|
|
3
3
|
import { createWriteVerbs } from "./event-store-executor-write.js";
|
|
4
|
+
import { withOwnTransactionOnPool } from "./event-store-executor-write-atomic.js";
|
|
4
5
|
export { WritePurposes } from "@cosmicdrift/kumiko-types/event-store-executor-types";
|
|
5
6
|
export { entityEventName } from "./event-store-executor-context.js";
|
|
6
7
|
export function createEventStoreExecutor(table, entity, options) {
|
|
7
8
|
const ctx = buildExecutorContext(table, entity, options);
|
|
8
9
|
return {
|
|
9
|
-
...createWriteVerbs(ctx),
|
|
10
|
+
...withOwnTransactionOnPool(createWriteVerbs(ctx)),
|
|
10
11
|
...createReadVerbs(ctx),
|
|
11
12
|
};
|
|
12
13
|
}
|
|
@@ -20,7 +20,7 @@ export function registerExecutorManagedWriteRunner(runner) {
|
|
|
20
20
|
executorManagedWriteRunners.add(runner);
|
|
21
21
|
}
|
|
22
22
|
// WeakSet.has never reads a property off runner, so a fail-closed guard Proxy stays untouched.
|
|
23
|
-
//
|
|
23
|
+
// Bun.SQL clients are callable (tagged templates), so a runner can be a function.
|
|
24
24
|
export function hasExecutorManagedWriteCapability(runner) {
|
|
25
25
|
if (typeof runner !== "object" && typeof runner !== "function")
|
|
26
26
|
return false;
|
package/dist/db/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { isTimestamptzType } from "./aggregate-sql.ts";
|
|
1
2
|
export { applyEntityEvent } from "./apply-entity-event.ts";
|
|
2
3
|
export { assertExistsIn } from "./assert-exists-in.ts";
|
|
3
4
|
export { nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, subjectRowExistsInTenant, } from "./blind-index-cleanup.ts";
|
|
@@ -10,6 +11,7 @@ export type { CursorQueryOptions, CursorResult, DecodedKeysetCursor } from "./cu
|
|
|
10
11
|
export { decodeCursor, decodeKeysetCursor, encodeCursor, encodeKeysetCursor } from "./cursor.ts";
|
|
11
12
|
export type { SchemaTable, SelectQuery, TableColumns } from "./dialect.ts";
|
|
12
13
|
export { bigint, bigserial, boolean, extractTableName, index, instant, instantToDriver, integer, jsonb, moneyAmount, numeric, primaryKey, serial, sql, table, text, timestamp, uniqueIndex, uuid, } from "./dialect.ts";
|
|
14
|
+
export { instantToTimestamptzParam } from "./driver-value-preparation.ts";
|
|
13
15
|
export type { EagerLoadEntityResolver, EagerLoadViewer, EagerloadedRow } from "./eagerload.ts";
|
|
14
16
|
export { collectReferenceFields, enrichRowWithReferences, enrichWithReferences, } from "./eagerload.ts";
|
|
15
17
|
export { collectEncryptedFieldNames, configuredEntityFieldEncryption, configureEntityFieldEncryption, decryptEntityFieldValues, encryptEntityFieldValues, } from "./entity-field-encryption.ts";
|
|
@@ -19,17 +21,18 @@ export { defineUnmanagedTable, deriveEntityTableMeta, } from "./entity-table-met
|
|
|
19
21
|
export type { EntityLifecycleVerb, EventStoreExecutor, EventStoreExecutorOptions, LockGuardOption, WritePurpose, } from "./event-store-executor.ts";
|
|
20
22
|
export { createEventStoreExecutor, entityEventName, WritePurposes, } from "./event-store-executor.ts";
|
|
21
23
|
export { enumerateFeatureTableSources, type FeatureTableSource, } from "./feature-table-sources.ts";
|
|
24
|
+
export { answerListAggregate, labelListAggregateGroups } from "./list-aggregate-labels.ts";
|
|
22
25
|
export { flattenLocatedTimestamp, type LocatedTimestampRead, rehydrateLocatedTimestamp, } from "./located-timestamp.ts";
|
|
23
26
|
export { assertUniqueTableNames, assertValidMigrationName, diffSnapshots, type GenerateMigrationInput, type GenerateMigrationOutput, generateMigration, loadSnapshotJson, renderMigrationSql, type SchemaDiff, type Snapshot, snapshotFromMetas, writeSnapshotJson, } from "./migrate-generator.ts";
|
|
24
27
|
export { type AppliedMigration, type ApplyResult, type BaselineResult, baselineMigrations, fetchAppliedMigrations, loadMigrationsFromDir, type Migration, MigrationChecksumMismatchError, readMigrationSqlTexts, runMigrations, runMigrationsFromDir, splitSqlStatements, } from "./migrate-runner.ts";
|
|
25
28
|
export { flattenMoney, type MoneyRead, moneyPayloadToMinorUnits, rehydrateMoney } from "./money.ts";
|
|
26
|
-
export { constraintOf, extractPgError, isTableAlreadyExists, isUniqueViolation, type PgErrorInfo, } from "./pg-error.ts";
|
|
29
|
+
export { constraintOf, extractPgError, isTableAlreadyExists, isUndefinedTable, isUniqueViolation, type PgErrorInfo, } from "./pg-error.ts";
|
|
27
30
|
export { acquireNamespacedAdvisoryLock } from "./queries/advisory-lock.ts";
|
|
28
31
|
export { readDatabaseNow } from "./queries/database-now.ts";
|
|
29
32
|
export { toPostgresArrayLiteral } from "./queries/postgres-array-literal.ts";
|
|
30
33
|
export { executeRawQuery, executeRawQueryRead } from "./queries/raw-sql.ts";
|
|
31
|
-
export type { DeleteManyBatchedOptions, DeleteManyBatchedResult, IncrementCounterOptions, InnerJoinRow, InnerJoinSpec, InsertOnConflictDoNothingOptions, JoinColumnPair, JsonTextMatch, SelectOptions,
|
|
32
|
-
export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched,
|
|
34
|
+
export type { DeleteManyBatchedOptions, DeleteManyBatchedResult, IncrementCounterOptions, InnerJoinRow, InnerJoinSpec, InsertOnConflictDoNothingOptions, JoinColumnPair, JsonTextMatch, SelectOptions, UpsertOnConflictOptions, WhereObject, WhereOperator, WhereValue, } from "./query.ts";
|
|
35
|
+
export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched, fetchOne, incrementCounter, insertMany, insertOnConflictDoNothing, insertOne, requireEntityTableMeta, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, selectInnerJoin, selectMany, transaction, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, } from "./query.ts";
|
|
33
36
|
export { readRebuildMarker, rebuildTablesFromDiff, writeRebuildMarker, } from "./rebuild-marker.ts";
|
|
34
37
|
export { seedReferenceData } from "./reference-data.ts";
|
|
35
38
|
export { renderTableDdl, renderTablesDdl } from "./render-ddl.ts";
|
|
@@ -38,5 +41,6 @@ export { findCommentedDropTables, isRetiredFrameworkTable, type RetiredFramework
|
|
|
38
41
|
export { tableExists } from "./schema-inspection.ts";
|
|
39
42
|
export { withoutStatementTimeout } from "./statement-timeout.ts";
|
|
40
43
|
export { buildBaseColumns, buildEntityTable, declareGlobalTenancy, type EntityRow, type EntityTable, type ExecutorManagedRunner, type ExecutorManagedWriteCapability, physicalColumnName, toSnakeCase, toTableName, type Writable, type WritableSchemaTable, type WritableTable, } from "./table-builder.ts";
|
|
44
|
+
export { extractTableInfo, type TableInfo } from "./table-info.ts";
|
|
41
45
|
export type { CreateTenantDbOptions, ExecutorManagedTenantDb, OutsideTransactionContext, TenantDb, TenantDbGrants, TenantDbMode, UncheckedSystemDb, } from "./tenant-db.ts";
|
|
42
46
|
export { castTenantRows, createSystemDbView, createTenantDataDestroyDb, createTenantDb, hasOutsideTransactionDb, requireOutsideTransactionDb, runInOwnTransaction, SYSTEM_SCOPE_CHECK_BRAND, scopeTenantDbToTenant, } from "./tenant-db.ts";
|
package/dist/db/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { isTimestamptzType } from "./aggregate-sql.js";
|
|
1
2
|
export { applyEntityEvent } from "./apply-entity-event.js";
|
|
2
3
|
export { assertExistsIn } from "./assert-exists-in.js";
|
|
3
4
|
export { nullBlindIndexesForSubject, recordEventsOwnedExclusivelyByTenant, recordRowExistsInTenant, recordRowOwningTenantId, subjectRowExistsInTenant, } from "./blind-index-cleanup.js";
|
|
@@ -7,22 +8,24 @@ export { seedConfigValues } from "./config-seed.js";
|
|
|
7
8
|
export { createDbConnection, DEFAULT_OUTSIDE_TRANSACTION_POOL_MAX, dbConnectionOptionsFromEnv, outsideTransactionPoolOptionsFromEnv, serverTimeoutOptionsFromEnv, } from "./connection.js";
|
|
8
9
|
export { decodeCursor, decodeKeysetCursor, encodeCursor, encodeKeysetCursor } from "./cursor.js";
|
|
9
10
|
export { bigint, bigserial, boolean, extractTableName, index, instant, instantToDriver, integer, jsonb, moneyAmount, numeric, primaryKey, serial, sql, table, text, timestamp, uniqueIndex, uuid, } from "./dialect.js";
|
|
11
|
+
export { instantToTimestamptzParam } from "./driver-value-preparation.js";
|
|
10
12
|
export { collectReferenceFields, enrichRowWithReferences, enrichWithReferences, } from "./eagerload.js";
|
|
11
13
|
export { collectEncryptedFieldNames, configuredEntityFieldEncryption, configureEntityFieldEncryption, decryptEntityFieldValues, encryptEntityFieldValues, } from "./entity-field-encryption.js";
|
|
12
14
|
export { entityTableFromRegistry } from "./entity-table-from-registry.js";
|
|
13
15
|
export { defineUnmanagedTable, deriveEntityTableMeta, } from "./entity-table-meta.js";
|
|
14
16
|
export { createEventStoreExecutor, entityEventName, WritePurposes, } from "./event-store-executor.js";
|
|
15
17
|
export { enumerateFeatureTableSources, } from "./feature-table-sources.js";
|
|
18
|
+
export { answerListAggregate, labelListAggregateGroups } from "./list-aggregate-labels.js";
|
|
16
19
|
export { flattenLocatedTimestamp, rehydrateLocatedTimestamp, } from "./located-timestamp.js";
|
|
17
20
|
export { assertUniqueTableNames, assertValidMigrationName, diffSnapshots, generateMigration, loadSnapshotJson, renderMigrationSql, snapshotFromMetas, writeSnapshotJson, } from "./migrate-generator.js";
|
|
18
21
|
export { baselineMigrations, fetchAppliedMigrations, loadMigrationsFromDir, MigrationChecksumMismatchError, readMigrationSqlTexts, runMigrations, runMigrationsFromDir, splitSqlStatements, } from "./migrate-runner.js";
|
|
19
22
|
export { flattenMoney, moneyPayloadToMinorUnits, rehydrateMoney } from "./money.js";
|
|
20
|
-
export { constraintOf, extractPgError, isTableAlreadyExists, isUniqueViolation, } from "./pg-error.js";
|
|
23
|
+
export { constraintOf, extractPgError, isTableAlreadyExists, isUndefinedTable, isUniqueViolation, } from "./pg-error.js";
|
|
21
24
|
export { acquireNamespacedAdvisoryLock } from "./queries/advisory-lock.js";
|
|
22
25
|
export { readDatabaseNow } from "./queries/database-now.js";
|
|
23
26
|
export { toPostgresArrayLiteral } from "./queries/postgres-array-literal.js";
|
|
24
27
|
export { executeRawQuery, executeRawQueryRead } from "./queries/raw-sql.js";
|
|
25
|
-
export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched,
|
|
28
|
+
export { aggregateWhere, asEntityTableMeta, asRawClient, countWhere, deleteMany, deleteManyBatched, fetchOne, incrementCounter, insertMany, insertOnConflictDoNothing, insertOne, requireEntityTableMeta, runInSavepoint, runInSavepointIfSupported, runnerCanBeginTransaction, selectInnerJoin, selectMany, transaction, unsafeReadRetrying, updateMany, upsertByPk, upsertOnConflict, } from "./query.js";
|
|
26
29
|
export { readRebuildMarker, rebuildTablesFromDiff, writeRebuildMarker, } from "./rebuild-marker.js";
|
|
27
30
|
export { seedReferenceData } from "./reference-data.js";
|
|
28
31
|
export { renderTableDdl, renderTablesDdl } from "./render-ddl.js";
|
|
@@ -31,4 +34,5 @@ export { findCommentedDropTables, isRetiredFrameworkTable, retiredFrameworkTable
|
|
|
31
34
|
export { tableExists } from "./schema-inspection.js";
|
|
32
35
|
export { withoutStatementTimeout } from "./statement-timeout.js";
|
|
33
36
|
export { buildBaseColumns, buildEntityTable, declareGlobalTenancy, physicalColumnName, toSnakeCase, toTableName, } from "./table-builder.js";
|
|
37
|
+
export { extractTableInfo } from "./table-info.js";
|
|
34
38
|
export { castTenantRows, createSystemDbView, createTenantDataDestroyDb, createTenantDb, hasOutsideTransactionDb, requireOutsideTransactionDb, runInOwnTransaction, SYSTEM_SCOPE_CHECK_BRAND, scopeTenantDbToTenant, } from "./tenant-db.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ListAggregateResult } from "@cosmicdrift/kumiko-types/list-aggregate-types";
|
|
2
|
+
import type { EntityDefinition } from "../engine/types/index.ts";
|
|
3
|
+
import type { EagerLoadEntityResolver, EagerLoadViewer } from "./eagerload.ts";
|
|
4
|
+
import type { EventStoreExecutor } from "./event-store-executor.ts";
|
|
5
|
+
import type { TenantDb } from "./tenant-db.ts";
|
|
6
|
+
type LabelDeps = {
|
|
7
|
+
readonly entity: EntityDefinition;
|
|
8
|
+
readonly resolveEntity: EagerLoadEntityResolver;
|
|
9
|
+
readonly viewer: EagerLoadViewer;
|
|
10
|
+
};
|
|
11
|
+
export declare function labelListAggregateGroups(result: ListAggregateResult, groupByField: string | undefined, deps: LabelDeps, db: TenantDb): Promise<ListAggregateResult>;
|
|
12
|
+
type AggregateRequest = Parameters<EventStoreExecutor["aggregate"]>[0];
|
|
13
|
+
export declare function answerListAggregate(executor: Pick<EventStoreExecutor, "aggregate">, request: AggregateRequest, user: Parameters<EventStoreExecutor["aggregate"]>[1], db: TenantDb, runtimeOptions: Parameters<EventStoreExecutor["aggregate"]>[3], labelDeps: LabelDeps): Promise<ListAggregateResult>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { enrichWithReferences } from "./eagerload.js";
|
|
2
|
+
function labelOf(ref, labelField) {
|
|
3
|
+
if (typeof ref !== "object" || ref === null || Array.isArray(ref))
|
|
4
|
+
return null;
|
|
5
|
+
const value = Reflect.get(ref, labelField);
|
|
6
|
+
return typeof value === "string" ? value : null;
|
|
7
|
+
}
|
|
8
|
+
// Labels come from the same eager-load path as list rows, so they carry its
|
|
9
|
+
// ownership and field-read gating instead of a second label query.
|
|
10
|
+
export async function labelListAggregateGroups(result, groupByField, deps, db) {
|
|
11
|
+
if (groupByField === undefined || result.groups.length === 0)
|
|
12
|
+
return result;
|
|
13
|
+
const def = deps.entity.fields[groupByField];
|
|
14
|
+
if (def?.type !== "reference" || def.multiple === true)
|
|
15
|
+
return result;
|
|
16
|
+
const enriched = await enrichWithReferences(result.groups.map((g) => ({ [groupByField]: g.key })), deps.entity, deps.resolveEntity, db, deps.viewer);
|
|
17
|
+
const groups = result.groups.map((group, i) => {
|
|
18
|
+
const ref = Reflect.get(enriched[i]?.["_refs"] ?? {}, groupByField);
|
|
19
|
+
return { ...group, label: labelOf(ref, def.labelField ?? "id") };
|
|
20
|
+
});
|
|
21
|
+
return { ...result, groups };
|
|
22
|
+
}
|
|
23
|
+
export async function answerListAggregate(executor, request, user, db, runtimeOptions, labelDeps) {
|
|
24
|
+
const result = await executor.aggregate(request, user, db, runtimeOptions);
|
|
25
|
+
return labelListAggregateGroups(result, request.aggregate.groupBy, labelDeps, db);
|
|
26
|
+
}
|
|
@@ -79,100 +79,85 @@ function indexesByName(meta) {
|
|
|
79
79
|
m.set(indexMetaKey(i), i);
|
|
80
80
|
return m;
|
|
81
81
|
}
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
nullabilityChanged: { from: prevCol.notNull, to: nextCol.notNull },
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
if (prevCol.defaultSql !== nextCol.defaultSql) {
|
|
101
|
-
Object.assign(change, {
|
|
102
|
-
defaultChanged: { from: prevCol.defaultSql, to: nextCol.defaultSql },
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
if (prevCol.pgType !== nextCol.pgType) {
|
|
106
|
-
Object.assign(change, {
|
|
107
|
-
typeChanged: { from: prevCol.pgType, to: nextCol.pgType },
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
if (change.nullabilityChanged || change.defaultChanged || change.typeChanged) {
|
|
111
|
-
changedColumns.push(change);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
for (const name of prevCols.keys()) {
|
|
115
|
-
if (!nextCols.has(name))
|
|
116
|
-
droppedColumns.push(name);
|
|
117
|
-
}
|
|
118
|
-
const prevIdx = indexesByName(prev);
|
|
119
|
-
const nextIdx = indexesByName(next);
|
|
120
|
-
const newIndexes = [];
|
|
121
|
-
const droppedIndexes = [];
|
|
122
|
-
const changedIndexes = [];
|
|
123
|
-
for (const [name, idx] of nextIdx) {
|
|
124
|
-
const prevI = prevIdx.get(name);
|
|
125
|
-
if (!prevI) {
|
|
126
|
-
newIndexes.push(idx);
|
|
82
|
+
function strictEqual(a, b) {
|
|
83
|
+
return a === b;
|
|
84
|
+
}
|
|
85
|
+
function fromToWhenDifferent(from, to, isEqual = strictEqual) {
|
|
86
|
+
return isEqual(from, to) ? undefined : { from, to };
|
|
87
|
+
}
|
|
88
|
+
// added and changed follow next's order, dropped follows prev's order; the
|
|
89
|
+
// rendered migration depends on both.
|
|
90
|
+
function diffByName(prev, next, compare) {
|
|
91
|
+
const added = [];
|
|
92
|
+
const changed = [];
|
|
93
|
+
for (const [name, nextItem] of next) {
|
|
94
|
+
const prevItem = prev.get(name);
|
|
95
|
+
if (prevItem === undefined) {
|
|
96
|
+
added.push(nextItem);
|
|
127
97
|
continue;
|
|
128
98
|
}
|
|
129
|
-
const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const uniqueChanged = (prevI.unique ?? false) === (idx.unique ?? false)
|
|
133
|
-
? undefined
|
|
134
|
-
: { from: prevI.unique ?? false, to: idx.unique ?? false };
|
|
135
|
-
// Whitespace-only re-rendering of the predicate must not drop and rebuild a large index.
|
|
136
|
-
const whereSqlChanged = whereSqlEqual(prevI.whereSql, idx.whereSql)
|
|
137
|
-
? undefined
|
|
138
|
-
: { from: prevI.whereSql, to: idx.whereSql };
|
|
139
|
-
const needsManualWhereChanged = (prevI.needsManualWhere ?? false) === (idx.needsManualWhere ?? false)
|
|
140
|
-
? undefined
|
|
141
|
-
: { from: prevI.needsManualWhere ?? false, to: idx.needsManualWhere ?? false };
|
|
142
|
-
if (columnsChanged || uniqueChanged || whereSqlChanged || needsManualWhereChanged) {
|
|
143
|
-
// Single literal typed as IndexChange so a misspelled key fails to compile instead of silently dropping the change.
|
|
144
|
-
const change = {
|
|
145
|
-
name,
|
|
146
|
-
...(columnsChanged && { columnsChanged }),
|
|
147
|
-
...(uniqueChanged && { uniqueChanged }),
|
|
148
|
-
...(whereSqlChanged && { whereSqlChanged }),
|
|
149
|
-
...(needsManualWhereChanged && { needsManualWhereChanged }),
|
|
150
|
-
};
|
|
151
|
-
changedIndexes.push(change);
|
|
152
|
-
}
|
|
99
|
+
const change = compare(name, prevItem, nextItem);
|
|
100
|
+
if (change !== undefined)
|
|
101
|
+
changed.push(change);
|
|
153
102
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
103
|
+
const dropped = [...prev.keys()].filter((name) => !next.has(name));
|
|
104
|
+
return { added, dropped, changed };
|
|
105
|
+
}
|
|
106
|
+
function compareColumns(name, prevCol, nextCol) {
|
|
107
|
+
const nullabilityChanged = fromToWhenDifferent(prevCol.notNull, nextCol.notNull);
|
|
108
|
+
const defaultChanged = fromToWhenDifferent(prevCol.defaultSql, nextCol.defaultSql);
|
|
109
|
+
const typeChanged = fromToWhenDifferent(prevCol.pgType, nextCol.pgType);
|
|
110
|
+
if (!nullabilityChanged && !defaultChanged && !typeChanged)
|
|
111
|
+
return undefined;
|
|
112
|
+
return {
|
|
113
|
+
name,
|
|
114
|
+
...(nullabilityChanged && { nullabilityChanged }),
|
|
115
|
+
...(defaultChanged && { defaultChanged }),
|
|
116
|
+
...(typeChanged && { typeChanged }),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function compareIndexes(name, prevIndex, nextIndex) {
|
|
120
|
+
const columnsChanged = fromToWhenDifferent(prevIndex.columns, nextIndex.columns, indexColumnsEqual);
|
|
121
|
+
const uniqueChanged = fromToWhenDifferent(prevIndex.unique ?? false, nextIndex.unique ?? false);
|
|
122
|
+
// Whitespace-only re-rendering of the predicate must not drop and rebuild a large index.
|
|
123
|
+
const whereSqlChanged = fromToWhenDifferent(prevIndex.whereSql, nextIndex.whereSql, whereSqlEqual);
|
|
124
|
+
const needsManualWhereChanged = fromToWhenDifferent(prevIndex.needsManualWhere ?? false, nextIndex.needsManualWhere ?? false);
|
|
125
|
+
if (!columnsChanged && !uniqueChanged && !whereSqlChanged && !needsManualWhereChanged) {
|
|
126
|
+
return undefined;
|
|
157
127
|
}
|
|
158
|
-
|
|
159
|
-
droppedColumns.length === 0 &&
|
|
160
|
-
changedColumns.length === 0 &&
|
|
161
|
-
newIndexes.length === 0 &&
|
|
162
|
-
droppedIndexes.length === 0 &&
|
|
163
|
-
changedIndexes.length === 0;
|
|
164
|
-
if (isEmpty)
|
|
165
|
-
return null;
|
|
128
|
+
// Single literal typed as IndexChange so a misspelled key fails to compile instead of silently dropping the change.
|
|
166
129
|
return {
|
|
130
|
+
name,
|
|
131
|
+
...(columnsChanged && { columnsChanged }),
|
|
132
|
+
...(uniqueChanged && { uniqueChanged }),
|
|
133
|
+
...(whereSqlChanged && { whereSqlChanged }),
|
|
134
|
+
...(needsManualWhereChanged && { needsManualWhereChanged }),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
function hasNoTableChanges(diff) {
|
|
138
|
+
return [
|
|
139
|
+
diff.newColumns,
|
|
140
|
+
diff.droppedColumns,
|
|
141
|
+
diff.changedColumns,
|
|
142
|
+
diff.newIndexes,
|
|
143
|
+
diff.droppedIndexes,
|
|
144
|
+
diff.changedIndexes,
|
|
145
|
+
].every((list) => list.length === 0);
|
|
146
|
+
}
|
|
147
|
+
function diffOneTable(prev, next) {
|
|
148
|
+
const columns = diffByName(columnsByName(prev), columnsByName(next), compareColumns);
|
|
149
|
+
const indexes = diffByName(indexesByName(prev), indexesByName(next), compareIndexes);
|
|
150
|
+
const diff = {
|
|
167
151
|
tableName: prev.tableName,
|
|
168
|
-
newColumns,
|
|
169
|
-
droppedColumns,
|
|
170
|
-
changedColumns,
|
|
171
|
-
newIndexes,
|
|
172
|
-
droppedIndexes,
|
|
173
|
-
changedIndexes,
|
|
152
|
+
newColumns: columns.added,
|
|
153
|
+
droppedColumns: columns.dropped,
|
|
154
|
+
changedColumns: columns.changed,
|
|
155
|
+
newIndexes: indexes.added,
|
|
156
|
+
droppedIndexes: indexes.dropped,
|
|
157
|
+
changedIndexes: indexes.changed,
|
|
174
158
|
nextMeta: next,
|
|
175
159
|
};
|
|
160
|
+
return hasNoTableChanges(diff) ? null : diff;
|
|
176
161
|
}
|
|
177
162
|
export function diffSnapshots(prev, next) {
|
|
178
163
|
const prevByName = new Map();
|
|
@@ -188,16 +188,16 @@ function migrationClient(db) {
|
|
|
188
188
|
if (hasBegin(client))
|
|
189
189
|
return client;
|
|
190
190
|
}
|
|
191
|
-
throw new Error("migrate-runner: db argument has no .unsafe() and .begin() (need a
|
|
191
|
+
throw new Error("migrate-runner: db argument has no .unsafe() and .begin() (need a Bun.SQL pool or a DbConnection)");
|
|
192
192
|
}
|
|
193
|
-
// Raw-SQL via
|
|
193
|
+
// Raw-SQL via Bun.SQL .unsafe().
|
|
194
194
|
async function executeRaw(db, sqlText) {
|
|
195
195
|
await migrationClient(db).unsafe(sqlText);
|
|
196
196
|
}
|
|
197
197
|
async function reserveConnection(db) {
|
|
198
198
|
const client = migrationClient(db);
|
|
199
199
|
if (typeof client.reserve !== "function") {
|
|
200
|
-
throw new Error("migrate-runner: db argument has no .reserve() (need a
|
|
200
|
+
throw new Error("migrate-runner: db argument has no .reserve() (need a Bun.SQL pool)");
|
|
201
201
|
}
|
|
202
202
|
return client.reserve();
|
|
203
203
|
}
|
|
@@ -280,7 +280,10 @@ export async function runMigrations(db, migrations) {
|
|
|
280
280
|
return { applied: appliedIds, skipped: skippedIds };
|
|
281
281
|
}
|
|
282
282
|
finally {
|
|
283
|
-
|
|
283
|
+
// A dropped session already released its lock; failing here would mask the migration error.
|
|
284
|
+
await conn
|
|
285
|
+
.unsafe(`SELECT pg_advisory_unlock(${MIGRATION_ADVISORY_LOCK_KEY})`)
|
|
286
|
+
.catch(() => undefined);
|
|
284
287
|
}
|
|
285
288
|
}
|
|
286
289
|
finally {
|
package/dist/db/pg-error.js
CHANGED
|
@@ -1,28 +1,33 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
// the idempotency-key index (caller-side replay signal).
|
|
1
|
+
// Bun.SQL server errors carry the SQLSTATE in `errno` and the constraint in
|
|
2
|
+
// `constraint` (`code` is the generic ERR_POSTGRES_SERVER_ERROR). Client-side
|
|
3
|
+
// failures have no `errno`, so their `code` (e.g. ERR_POSTGRES_CONNECTION_CLOSED)
|
|
4
|
+
// is returned instead. The `.cause` chain is walked so wrapped errors resolve too.
|
|
5
|
+
import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
7
6
|
const MAX_CAUSE_DEPTH = 8;
|
|
7
|
+
function stringOrUndefined(value) {
|
|
8
|
+
return typeof value === "string" ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
function infoOfLayer(layer) {
|
|
11
|
+
const sqlState = stringOrUndefined(propertyOf(layer, "errno"));
|
|
12
|
+
if (sqlState !== undefined) {
|
|
13
|
+
return {
|
|
14
|
+
code: sqlState,
|
|
15
|
+
constraint_name: stringOrUndefined(propertyOf(layer, "constraint")),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const code = stringOrUndefined(propertyOf(layer, "code"));
|
|
19
|
+
return code === undefined ? null : { code, constraint_name: undefined };
|
|
20
|
+
}
|
|
8
21
|
export function extractPgError(e) {
|
|
9
|
-
if (typeof e !== "object" || e === null)
|
|
10
|
-
return null;
|
|
11
|
-
const layers = [];
|
|
12
22
|
let current = e;
|
|
13
23
|
// Depth cap doubles as cycle protection for self-referential causes.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const code = layer.code;
|
|
22
|
-
const constraintName = layer.constraint_name; // @cast-boundary error-details
|
|
23
|
-
if (code !== undefined || constraintName !== undefined) {
|
|
24
|
-
return { code, constraint_name: constraintName };
|
|
25
|
-
}
|
|
24
|
+
for (let depth = 0; depth < MAX_CAUSE_DEPTH; depth++) {
|
|
25
|
+
if (typeof current !== "object" || current === null)
|
|
26
|
+
return null;
|
|
27
|
+
const info = infoOfLayer(current);
|
|
28
|
+
if (info !== null)
|
|
29
|
+
return info;
|
|
30
|
+
current = propertyOf(current, "cause");
|
|
26
31
|
}
|
|
27
32
|
return null;
|
|
28
33
|
}
|
|
@@ -499,7 +499,7 @@ async function rekeyTenantKeyedValue(deps, target) {
|
|
|
499
499
|
const userSubject = keyedUnder?.kind === "tenant" && keyedUnder.tenantId === target.tenantId
|
|
500
500
|
? rekeyTargetOfTenantKeyedValue(target)
|
|
501
501
|
: keyedUnder?.kind === "user"
|
|
502
|
-
? currentProjectionOwnerIfOther(target, keyedUnder.userId)
|
|
502
|
+
? currentProjectionOwnerIfOther(target, fieldDef.userOwned.ownerField, keyedUnder.userId)
|
|
503
503
|
: null;
|
|
504
504
|
if (userSubject === null)
|
|
505
505
|
return { kind: "unchanged" };
|
|
@@ -536,11 +536,8 @@ function rekeyTargetOfTenantKeyedValue(target) {
|
|
|
536
536
|
// A value keyed under a previous owner moves to the owner the row has now. The
|
|
537
537
|
// projection of the event's own tenant is authoritative here: the payload of
|
|
538
538
|
// an old created event still names the owner the row had back then.
|
|
539
|
-
function currentProjectionOwnerIfOther(target, keyedUserId) {
|
|
540
|
-
const
|
|
541
|
-
if (fieldDef === undefined || !("userOwned" in fieldDef) || !fieldDef.userOwned)
|
|
542
|
-
return null;
|
|
543
|
-
const owner = nonEmptyString(target.projectionOwnerRow?.[fieldDef.userOwned.ownerField]);
|
|
539
|
+
function currentProjectionOwnerIfOther(target, ownerField, keyedUserId) {
|
|
540
|
+
const owner = nonEmptyString(target.projectionOwnerRow?.[ownerField]);
|
|
544
541
|
return owner === null || owner === keyedUserId ? null : { kind: "user", userId: owner };
|
|
545
542
|
}
|
|
546
543
|
// Only the row's own tenant key or a user key counts: another tenant's key is
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { executeRawQueryRead } from "./raw-sql.js";
|
|
2
2
|
// Called by createTenantDb with its inner runner; keeps raw SQL out of consumers.
|
|
3
|
+
// timestamptz(3): events.created_at has millisecond precision, a microsecond now() would compare later.
|
|
3
4
|
export async function queryDatabaseNow(runner) {
|
|
4
|
-
const [row] = await executeRawQueryRead(runner, "SELECT now() AS now");
|
|
5
|
+
const [row] = await executeRawQueryRead(runner, "SELECT now()::timestamptz(3) AS now");
|
|
5
6
|
if (!row)
|
|
6
7
|
throw new Error("SELECT now() returned no row");
|
|
7
8
|
return row.now;
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
// partial index whose WHERE the renderer can't express is rejected up-front.
|
|
20
20
|
import { isUuid, parseTenantId } from "@cosmicdrift/kumiko-types/identifiers";
|
|
21
21
|
import { configuredBlindIndexKey } from "../../crypto/index.js";
|
|
22
|
+
import { extractPgError } from "../pg-error.js";
|
|
22
23
|
import { asEntityTableMeta, asRawClient } from "../query.js";
|
|
23
24
|
import { renderTableDdl } from "../render-ddl.js";
|
|
24
25
|
import { columnNamesOf, tableExists } from "../schema-inspection.js";
|
|
@@ -27,9 +28,7 @@ import { quoteTableIdent } from "./table-ops.js";
|
|
|
27
28
|
export const PROJECTION_REBUILD_SCHEMA = "kumiko_rebuild";
|
|
28
29
|
const SCHEMA_IDENT = quoteTableIdent(PROJECTION_REBUILD_SCHEMA);
|
|
29
30
|
function isDuplicateSchemaError(e) {
|
|
30
|
-
|
|
31
|
-
return false;
|
|
32
|
-
const { code } = e;
|
|
31
|
+
const code = extractPgError(e)?.code;
|
|
33
32
|
// 42P06 duplicate_schema, 23505 unique_violation on pg_namespace — both
|
|
34
33
|
// surface from the well-known CREATE SCHEMA IF NOT EXISTS race.
|
|
35
34
|
return code === "42P06" || code === "23505";
|
package/dist/db/query.d.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { AggregateRow, AggregateSpec } from "@cosmicdrift/kumiko-types/aggregate-types";
|
|
2
2
|
import type { DbRunner, DbTx } from "@cosmicdrift/kumiko-types/db-connection";
|
|
3
3
|
import type { ExecutorManagedRunner, ExecutorManagedWriteCapability, WritableTable } from "@cosmicdrift/kumiko-types/executor-brand";
|
|
4
|
-
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
5
4
|
import type { SelectOptions, WhereObject } from "@cosmicdrift/kumiko-types/where-clause-types";
|
|
5
|
+
import { type ClosedConnectionContext } from "./closed-connection.ts";
|
|
6
|
+
import { type PreparedValue } from "./driver-value-preparation.ts";
|
|
6
7
|
import type { EntityTableMeta } from "./entity-table-meta.ts";
|
|
8
|
+
import { type TableInfo } from "./table-info.ts";
|
|
7
9
|
import { asEntityTableMeta, requireEntityTableMeta } from "./table-introspection.ts";
|
|
8
10
|
export { asEntityTableMeta, requireEntityTableMeta };
|
|
9
11
|
export type ReservedClient = {
|
|
@@ -30,20 +32,9 @@ export declare function runInSavepointIfSupported<T>(db: unknown, fn: (sp: DbRun
|
|
|
30
32
|
export type AnyDb = DbRunner | unknown;
|
|
31
33
|
type AnyRow = any;
|
|
32
34
|
export type { JsonTextMatch, OrderByClause, SelectOptions, WhereObject, WhereOperator, WhereValue, } from "@cosmicdrift/kumiko-types/where-clause-types";
|
|
33
|
-
type TableLike = EntityTableMeta | any;
|
|
34
|
-
export type TableInfo = {
|
|
35
|
-
readonly name: string;
|
|
36
|
-
readonly columnOf: (field: string) => string;
|
|
37
|
-
readonly pgTypeOf: (column: string) => string | undefined;
|
|
38
|
-
readonly bigintJsModeOf: (column: string) => "number" | "bigint" | undefined;
|
|
39
|
-
readonly fieldOf: (column: string) => string;
|
|
40
|
-
readonly hasColumn: (fieldOrColumn: string) => boolean;
|
|
41
|
-
};
|
|
42
|
-
export declare function extractTableInfo(table: TableLike): TableInfo;
|
|
35
|
+
export type TableLike = EntityTableMeta | any;
|
|
43
36
|
export declare function coerceRow<TOut = Record<string, unknown>>(row: Record<string, unknown>, info: TableInfo): TOut;
|
|
44
|
-
export declare function
|
|
45
|
-
export declare function isClosedConnectionError(err: unknown): boolean;
|
|
46
|
-
export declare function describeClosedConnectionFailure(raw: unknown, err: unknown, attempts: number): Record<string, unknown> | undefined;
|
|
37
|
+
export declare function unsafeLoggingClosedConnection<TRow = unknown>(db: AnyDb, sqlText: string, params: readonly unknown[], context: ClosedConnectionContext): Promise<readonly TRow[]>;
|
|
47
38
|
export declare function unsafeReadRetrying<TRow>(db: AnyDb, sqlText: string, params: readonly unknown[]): Promise<readonly TRow[]>;
|
|
48
39
|
export declare function selectMany<TRow = AnyRow>(db: AnyDb, table: TableLike, where?: WhereObject, options?: SelectOptions): Promise<readonly TRow[]>;
|
|
49
40
|
export declare function fetchOne<TRow = AnyRow>(db: AnyDb, table: TableLike, where: WhereObject): Promise<TRow | undefined>;
|
|
@@ -75,7 +66,18 @@ export declare function updateMany<TRow = AnyRow>(db: AnyDb, table: WritableTabl
|
|
|
75
66
|
export declare function updateMany<TRow = AnyRow>(db: ExecutorManagedWriteCapability, table: EntityTableMeta, set: Record<string, unknown>, where: WhereObject): Promise<readonly TRow[]>;
|
|
76
67
|
export declare function deleteMany(db: AnyDb, table: WritableTable, where: WhereObject): Promise<number>;
|
|
77
68
|
export declare function deleteMany(db: ExecutorManagedWriteCapability, table: EntityTableMeta, where: WhereObject): Promise<number>;
|
|
69
|
+
export type InsertEntry = {
|
|
70
|
+
readonly field: string;
|
|
71
|
+
readonly col: string;
|
|
72
|
+
readonly prepared: PreparedValue;
|
|
73
|
+
};
|
|
74
|
+
export declare function insertEntries(info: TableInfo, values: Record<string, unknown>): InsertEntry[];
|
|
78
75
|
export declare function resolveConflictColumns(table: TableLike, info: TableInfo, conflictKeys: readonly string[] | undefined): readonly string[];
|
|
76
|
+
export declare function conflictUpdateParts(info: TableInfo, entries: readonly InsertEntry[], update: Record<string, unknown> | undefined, skipCols: ReadonlySet<string>, params: unknown[]): string[];
|
|
77
|
+
export declare function buildInsertSql(info: TableInfo, entries: readonly InsertEntry[]): {
|
|
78
|
+
sqlPrefix: string;
|
|
79
|
+
params: unknown[];
|
|
80
|
+
};
|
|
79
81
|
export type UpsertOnConflictOptions = {
|
|
80
82
|
readonly conflictKeys: readonly string[];
|
|
81
83
|
/** Columns to set on conflict. Default: EXCLUDED for every inserted non-key column. */
|
|
@@ -92,7 +94,6 @@ export type DeleteManyBatchedResult = {
|
|
|
92
94
|
readonly batches: number;
|
|
93
95
|
};
|
|
94
96
|
export declare function countWhere(db: AnyDb, table: TableLike, where?: WhereObject): Promise<number>;
|
|
95
|
-
export declare function isTimestamptzType(pgType: string | undefined): boolean;
|
|
96
97
|
export declare function aggregateWhere(db: AnyDb, table: TableLike, spec: AggregateSpec, where?: WhereObject): Promise<readonly AggregateRow[]>;
|
|
97
98
|
export declare function upsertOnConflict<TRow = AnyRow>(db: AnyDb, table: WritableTable, values: Record<string, unknown>, options: UpsertOnConflictOptions): Promise<TRow | undefined>;
|
|
98
99
|
export declare function upsertOnConflict<TRow = AnyRow>(db: ExecutorManagedWriteCapability, table: EntityTableMeta, values: Record<string, unknown>, options: UpsertOnConflictOptions): Promise<TRow | undefined>;
|