@beechcms/core 0.8.0 → 0.9.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/dist/auth/account-email.d.ts +3 -0
- package/dist/auth/account-email.d.ts.map +1 -0
- package/dist/auth/account-email.js +9 -0
- package/dist/auth/password-reset-token.repository.d.ts +13 -2
- package/dist/auth/password-reset-token.repository.d.ts.map +1 -1
- package/dist/auth/user.repository.d.ts +69 -4
- package/dist/auth/user.repository.d.ts.map +1 -1
- package/dist/automations-grammar-words.d.ts +2 -0
- package/dist/automations-grammar-words.d.ts.map +1 -0
- package/dist/automations-grammar-words.js +8 -0
- package/dist/automations.repository.interface.d.ts +19 -0
- package/dist/automations.repository.interface.d.ts.map +1 -0
- package/dist/automations.repository.interface.js +3 -0
- package/dist/automations.runner.interface.d.ts +10 -0
- package/dist/automations.runner.interface.d.ts.map +1 -0
- package/dist/automations.runner.interface.js +3 -0
- package/dist/automations.runner.stub.d.ts +5 -0
- package/dist/automations.runner.stub.d.ts.map +1 -0
- package/dist/automations.runner.stub.js +7 -0
- package/dist/automations.types.d.ts +75 -0
- package/dist/automations.types.d.ts.map +1 -0
- package/dist/automations.types.js +3 -0
- package/dist/clock.d.ts +25 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +11 -0
- package/dist/common/canonical-json.d.ts +31 -0
- package/dist/common/canonical-json.d.ts.map +1 -0
- package/dist/common/canonical-json.js +91 -0
- package/dist/content/content-scan.repository.d.ts +1 -1
- package/dist/content/content.repository.d.ts +154 -3
- package/dist/content/content.repository.d.ts.map +1 -1
- package/dist/content/content.repository.js +62 -0
- package/dist/content/deletion-ledger.d.ts +39 -0
- package/dist/content/deletion-ledger.d.ts.map +1 -0
- package/dist/content/deletion-ledger.js +3 -0
- package/dist/content/seed-media-purge.repository.d.ts +34 -0
- package/dist/content/seed-media-purge.repository.d.ts.map +1 -0
- package/dist/content/seed-media-purge.repository.js +3 -0
- package/dist/content/seed.repository.d.ts +14 -0
- package/dist/content/seed.repository.d.ts.map +1 -1
- package/dist/content-scan.repository.d.ts +9 -0
- package/dist/content-scan.repository.d.ts.map +1 -0
- package/dist/content-scan.repository.js +3 -0
- package/dist/content.repository.d.ts +247 -0
- package/dist/content.repository.d.ts.map +1 -0
- package/dist/content.repository.js +59 -0
- package/dist/dashboard-layout/content-view.d.ts +757 -0
- package/dist/dashboard-layout/content-view.d.ts.map +1 -0
- package/dist/dashboard-layout/content-view.js +285 -0
- package/dist/dashboard-layout/content-view.repository.d.ts +39 -0
- package/dist/dashboard-layout/content-view.repository.d.ts.map +1 -0
- package/dist/dashboard-layout/content-view.repository.js +3 -0
- package/dist/dashboard-layout/dashboard-layout.d.ts +5 -0
- package/dist/dashboard-layout/dashboard-layout.d.ts.map +1 -1
- package/dist/dashboard-layout/dashboard-layout.js +17 -9
- package/dist/dashboard-layout/kanban/kanban.d.ts +32 -18
- package/dist/dashboard-layout/kanban/kanban.d.ts.map +1 -1
- package/dist/dashboard-layout/kanban/kanban.js +45 -21
- package/dist/dashboard-layout/seed-layout.d.ts +22 -31
- package/dist/dashboard-layout/seed-layout.d.ts.map +1 -1
- package/dist/dashboard-layout/seed-layout.js +93 -18
- package/dist/dashboard-layout/seed-layout.repository.d.ts +1 -5
- package/dist/dashboard-layout/seed-layout.repository.d.ts.map +1 -1
- package/dist/dashboard-layout.d.ts +154 -0
- package/dist/dashboard-layout.d.ts.map +1 -0
- package/dist/dashboard-layout.js +186 -0
- package/dist/dashboard-layout.repository.d.ts +18 -0
- package/dist/dashboard-layout.repository.d.ts.map +1 -0
- package/dist/dashboard-layout.repository.js +3 -0
- package/dist/dashboard-permissions.d.ts +3 -0
- package/dist/dashboard-permissions.d.ts.map +1 -0
- package/dist/dashboard-permissions.js +11 -0
- package/dist/dashboard-scopes.d.ts +12 -0
- package/dist/dashboard-scopes.d.ts.map +1 -0
- package/dist/dashboard-scopes.js +30 -0
- package/dist/define-seed.d.ts +3 -0
- package/dist/define-seed.d.ts.map +1 -0
- package/dist/define-seed.js +5 -0
- package/dist/demo-data.repository.d.ts +5 -0
- package/dist/demo-data.repository.d.ts.map +1 -0
- package/dist/demo-data.repository.js +3 -0
- package/dist/email.provider.d.ts +32 -0
- package/dist/email.provider.d.ts.map +1 -0
- package/dist/email.provider.js +4 -0
- package/dist/engine/ddl/ddl.d.ts +247 -0
- package/dist/engine/ddl/ddl.d.ts.map +1 -0
- package/dist/engine/ddl/ddl.js +653 -0
- package/dist/engine/ddl/schema-mutator.d.ts +29 -0
- package/dist/engine/ddl/schema-mutator.d.ts.map +1 -0
- package/dist/engine/ddl/schema-mutator.js +3 -0
- package/dist/engine/ddl/seed-ddl-destructive.d.ts +40 -0
- package/dist/engine/ddl/seed-ddl-destructive.d.ts.map +1 -0
- package/dist/engine/ddl/seed-ddl-destructive.js +149 -0
- package/dist/engine/ddl/seed-ddl.d.ts +43 -0
- package/dist/engine/ddl/seed-ddl.d.ts.map +1 -0
- package/dist/engine/ddl/seed-ddl.js +115 -0
- package/dist/engine/ddl/seed-purge-guards.d.ts +7 -0
- package/dist/engine/ddl/seed-purge-guards.d.ts.map +1 -0
- package/dist/engine/ddl/seed-purge-guards.js +19 -0
- package/dist/engine/engine.d.ts +4 -3
- package/dist/engine/engine.d.ts.map +1 -1
- package/dist/engine/engine.js +4 -3
- package/dist/engine/introspection/introspection.d.ts +101 -0
- package/dist/engine/introspection/introspection.d.ts.map +1 -0
- package/dist/engine/introspection/introspection.js +127 -0
- package/dist/engine/introspection/relation-audit.d.ts +46 -0
- package/dist/engine/introspection/relation-audit.d.ts.map +1 -0
- package/dist/engine/introspection/relation-audit.js +103 -0
- package/dist/engine/introspection/schema-fingerprint.d.ts +74 -0
- package/dist/engine/introspection/schema-fingerprint.d.ts.map +1 -0
- package/dist/engine/introspection/schema-fingerprint.js +102 -0
- package/dist/engine/introspection.d.ts +101 -0
- package/dist/engine/introspection.d.ts.map +1 -0
- package/dist/engine/introspection.js +127 -0
- package/dist/engine/localization/localization.d.ts +127 -0
- package/dist/engine/localization/localization.d.ts.map +1 -0
- package/dist/engine/localization/localization.js +212 -0
- package/dist/engine/localization.d.ts +127 -0
- package/dist/engine/localization.d.ts.map +1 -0
- package/dist/engine/localization.js +212 -0
- package/dist/engine/privacy/policies.d.ts +58 -0
- package/dist/engine/privacy/policies.d.ts.map +1 -0
- package/dist/engine/privacy/policies.js +191 -0
- package/dist/engine/privacy/privacy.service.d.ts +78 -0
- package/dist/engine/privacy/privacy.service.d.ts.map +1 -0
- package/dist/engine/privacy/privacy.service.js +138 -0
- package/dist/engine/privacy.service.d.ts.map +1 -1
- package/dist/engine/query/active-clause.d.ts +19 -0
- package/dist/engine/query/active-clause.d.ts.map +1 -0
- package/dist/engine/query/active-clause.js +27 -0
- package/dist/engine/query/query.d.ts +36 -0
- package/dist/engine/query/query.d.ts.map +1 -0
- package/dist/engine/query/query.js +393 -0
- package/dist/engine/query/relations.d.ts +28 -0
- package/dist/engine/query/relations.d.ts.map +1 -0
- package/dist/engine/query/relations.js +25 -0
- package/dist/engine/query/serialize.d.ts +22 -0
- package/dist/engine/query/serialize.d.ts.map +1 -0
- package/dist/engine/query/serialize.js +175 -0
- package/dist/engine/schema-fingerprint.d.ts +73 -0
- package/dist/engine/schema-fingerprint.d.ts.map +1 -0
- package/dist/engine/schema-fingerprint.js +97 -0
- package/dist/engine/seed-registry.d.ts.map +1 -1
- package/dist/engine/seeds/candidate-ids.d.ts +14 -0
- package/dist/engine/seeds/candidate-ids.d.ts.map +1 -0
- package/dist/engine/seeds/candidate-ids.js +40 -0
- package/dist/engine/seeds/define-seed.d.ts +3 -0
- package/dist/engine/seeds/define-seed.d.ts.map +1 -0
- package/dist/engine/seeds/define-seed.js +5 -0
- package/dist/engine/seeds/seed-definition-diff.d.ts +38 -0
- package/dist/engine/seeds/seed-definition-diff.d.ts.map +1 -0
- package/dist/engine/seeds/seed-definition-diff.js +51 -0
- package/dist/engine/seeds/seed-registry.d.ts +88 -0
- package/dist/engine/seeds/seed-registry.d.ts.map +1 -0
- package/dist/engine/seeds/seed-registry.js +194 -0
- package/dist/engine/seeds/seed-types-generator.d.ts +25 -0
- package/dist/engine/seeds/seed-types-generator.d.ts.map +1 -0
- package/dist/engine/seeds/seed-types-generator.js +116 -0
- package/dist/engine/seeds/seed-validation.d.ts +35 -0
- package/dist/engine/seeds/seed-validation.d.ts.map +1 -0
- package/dist/engine/seeds/seed-validation.js +384 -0
- package/dist/engine/seeds/seeds.d.ts +20 -0
- package/dist/engine/seeds/seeds.d.ts.map +1 -0
- package/dist/engine/seeds/seeds.js +21 -0
- package/dist/engine/seeds/tag-migration.d.ts +73 -0
- package/dist/engine/seeds/tag-migration.d.ts.map +1 -0
- package/dist/engine/seeds/tag-migration.js +212 -0
- package/dist/engine/seeds/tag-options.d.ts +15 -0
- package/dist/engine/seeds/tag-options.d.ts.map +1 -0
- package/dist/engine/seeds/tag-options.js +111 -0
- package/dist/engine/seeds/tag-value.d.ts +31 -0
- package/dist/engine/seeds/tag-value.d.ts.map +1 -0
- package/dist/engine/seeds/tag-value.js +51 -0
- package/dist/engine/types.d.ts +59 -7
- package/dist/engine/types.d.ts.map +1 -1
- package/dist/engine/validation/cache.d.ts.map +1 -1
- package/dist/engine/validation/cache.js +20 -4
- package/dist/engine/validation/emptiness.d.ts +12 -0
- package/dist/engine/validation/emptiness.d.ts.map +1 -0
- package/dist/engine/validation/emptiness.js +33 -0
- package/dist/engine/validation/index.d.ts +11 -0
- package/dist/engine/validation/index.d.ts.map +1 -1
- package/dist/engine/validation/index.js +29 -33
- package/dist/engine/validation/primitives.d.ts +12 -0
- package/dist/engine/validation/primitives.d.ts.map +1 -1
- package/dist/engine/validation/primitives.js +22 -0
- package/dist/engine/validation/richtext-sanitizer.d.ts +9 -1
- package/dist/engine/validation/richtext-sanitizer.d.ts.map +1 -1
- package/dist/engine/validation/richtext-sanitizer.js +36 -7
- package/dist/engine/validation/schema-builders.d.ts +16 -0
- package/dist/engine/validation/schema-builders.d.ts.map +1 -1
- package/dist/engine/validation/schema-builders.js +125 -18
- package/dist/engine.d.ts +144 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +741 -0
- package/dist/file-types.d.ts +13 -0
- package/dist/file-types.d.ts.map +1 -0
- package/dist/file-types.js +85 -0
- package/dist/hooks.d.ts +29 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +3 -0
- package/dist/id-generator.d.ts +26 -0
- package/dist/id-generator.d.ts.map +1 -0
- package/dist/id-generator.js +12 -0
- package/dist/idempotency.repository.d.ts +13 -0
- package/dist/idempotency.repository.d.ts.map +1 -0
- package/dist/idempotency.repository.js +3 -0
- package/dist/index.d.ts +34 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -11
- package/dist/kanban-position.repository.d.ts +19 -0
- package/dist/kanban-position.repository.d.ts.map +1 -0
- package/dist/kanban-position.repository.js +3 -0
- package/dist/kanban.d.ts +75 -0
- package/dist/kanban.d.ts.map +1 -0
- package/dist/kanban.js +82 -0
- package/dist/layout-permissions.d.ts +3 -0
- package/dist/layout-permissions.d.ts.map +1 -0
- package/dist/layout-permissions.js +11 -0
- package/dist/media/file-types.d.ts +12 -0
- package/dist/media/file-types.d.ts.map +1 -1
- package/dist/media/file-types.js +24 -4
- package/dist/media/image-transformer.d.ts +34 -0
- package/dist/media/image-transformer.d.ts.map +1 -0
- package/dist/media/image-transformer.js +3 -0
- package/dist/media/magic-bytes.d.ts.map +1 -1
- package/dist/media/magic-bytes.js +19 -9
- package/dist/media/media-transform.d.ts +92 -0
- package/dist/media/media-transform.d.ts.map +1 -0
- package/dist/media/media-transform.js +197 -0
- package/dist/media/media.repository.d.ts +5 -0
- package/dist/media/media.repository.d.ts.map +1 -1
- package/dist/media.repository.d.ts +61 -0
- package/dist/media.repository.d.ts.map +1 -0
- package/dist/media.repository.js +3 -0
- package/dist/notifications/notification.repository.d.ts +11 -2
- package/dist/notifications/notification.repository.d.ts.map +1 -1
- package/dist/oauth/authorization-code.repository.d.ts +10 -5
- package/dist/oauth/authorization-code.repository.d.ts.map +1 -1
- package/dist/oauth/role-guard.d.ts +30 -11
- package/dist/oauth/role-guard.d.ts.map +1 -1
- package/dist/oauth/role-guard.js +27 -5
- package/dist/oauth/token.repository.d.ts +2 -0
- package/dist/oauth/token.repository.d.ts.map +1 -1
- package/dist/policies.d.ts +10 -0
- package/dist/policies.d.ts.map +1 -0
- package/dist/policies.js +33 -0
- package/dist/queue/queue.interface.d.ts +9 -1
- package/dist/queue/queue.interface.d.ts.map +1 -1
- package/dist/queue/queue.stub.d.ts +1 -1
- package/dist/queue/queue.stub.d.ts.map +1 -1
- package/dist/queue/queue.stub.js +2 -3
- package/dist/queue.interface.d.ts +39 -0
- package/dist/queue.interface.d.ts.map +1 -0
- package/dist/queue.interface.js +3 -0
- package/dist/queue.stub.d.ts +6 -0
- package/dist/queue.stub.d.ts.map +1 -0
- package/dist/queue.stub.js +8 -0
- package/dist/rate-limit/token-bucket-rate-limiter.d.ts +7 -0
- package/dist/rate-limit/token-bucket-rate-limiter.d.ts.map +1 -1
- package/dist/rate-limit/token-bucket-rate-limiter.js +66 -0
- package/dist/rbac/evaluate.d.ts +57 -0
- package/dist/rbac/evaluate.d.ts.map +1 -0
- package/dist/rbac/evaluate.js +113 -0
- package/dist/rbac/invitation.repository.d.ts +84 -0
- package/dist/rbac/invitation.repository.d.ts.map +1 -0
- package/dist/rbac/invitation.repository.js +3 -0
- package/dist/rbac/permissions.d.ts +39 -0
- package/dist/rbac/permissions.d.ts.map +1 -0
- package/dist/rbac/permissions.js +43 -0
- package/dist/rbac/types.d.ts +130 -0
- package/dist/rbac/types.d.ts.map +1 -0
- package/dist/rbac/types.js +4 -0
- package/dist/relations.d.ts +28 -0
- package/dist/relations.d.ts.map +1 -0
- package/dist/relations.js +25 -0
- package/dist/richtext-render.d.ts +11 -0
- package/dist/richtext-render.d.ts.map +1 -0
- package/dist/richtext-render.js +87 -0
- package/dist/richtext.d.ts +11 -0
- package/dist/richtext.d.ts.map +1 -0
- package/dist/richtext.js +13 -0
- package/dist/scheduler.interface.d.ts +4 -0
- package/dist/scheduler.interface.d.ts.map +1 -0
- package/dist/scheduler.interface.js +3 -0
- package/dist/scheduler.stub.d.ts +5 -0
- package/dist/scheduler.stub.d.ts.map +1 -0
- package/dist/scheduler.stub.js +7 -0
- package/dist/schema/canonical.d.ts +15 -0
- package/dist/schema/canonical.d.ts.map +1 -0
- package/dist/schema/canonical.js +37 -0
- package/dist/schema/define.d.ts +42 -0
- package/dist/schema/define.d.ts.map +1 -0
- package/dist/schema/define.js +56 -0
- package/dist/schema/emit.d.ts +14 -0
- package/dist/schema/emit.d.ts.map +1 -0
- package/dist/schema/emit.js +43 -0
- package/dist/schema/index.d.ts +12 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +13 -0
- package/dist/schema/manifest-seeds.d.ts +12 -0
- package/dist/schema/manifest-seeds.d.ts.map +1 -0
- package/dist/schema/manifest-seeds.js +48 -0
- package/dist/schema/manifest-validation.d.ts +13 -0
- package/dist/schema/manifest-validation.d.ts.map +1 -0
- package/dist/schema/manifest-validation.js +41 -0
- package/dist/schema/manifest.types.d.ts +54 -0
- package/dist/schema/manifest.types.d.ts.map +1 -0
- package/dist/schema/manifest.types.js +7 -0
- package/dist/schema-mutator.d.ts +26 -0
- package/dist/schema-mutator.d.ts.map +1 -0
- package/dist/schema-mutator.js +3 -0
- package/dist/search/search.repository.d.ts +5 -4
- package/dist/search/search.repository.d.ts.map +1 -1
- package/dist/search/vector-extractor.d.ts.map +1 -1
- package/dist/search/vector-extractor.js +23 -2
- package/dist/search/vector.repository.d.ts +2 -1
- package/dist/search/vector.repository.d.ts.map +1 -1
- package/dist/security/time-trap-token.repository.d.ts +5 -3
- package/dist/security/time-trap-token.repository.d.ts.map +1 -1
- package/dist/seed-ddl-destructive.d.ts +40 -0
- package/dist/seed-ddl-destructive.d.ts.map +1 -0
- package/dist/seed-ddl-destructive.js +149 -0
- package/dist/seed-ddl.d.ts +40 -0
- package/dist/seed-ddl.d.ts.map +1 -0
- package/dist/seed-ddl.js +100 -0
- package/dist/seed-layout.d.ts +145 -0
- package/dist/seed-layout.d.ts.map +1 -0
- package/dist/seed-layout.js +192 -0
- package/dist/seed-layout.repository.d.ts +22 -0
- package/dist/seed-layout.repository.d.ts.map +1 -0
- package/dist/seed-layout.repository.js +3 -0
- package/dist/seed-registry.d.ts +71 -0
- package/dist/seed-registry.d.ts.map +1 -0
- package/dist/seed-registry.js +143 -0
- package/dist/seed-types-generator.d.ts +1 -1
- package/dist/seed-types-generator.d.ts.map +1 -1
- package/dist/seed-validation.d.ts +23 -0
- package/dist/seed-validation.d.ts.map +1 -0
- package/dist/seed-validation.js +224 -0
- package/dist/seed.repository.d.ts +37 -0
- package/dist/seed.repository.d.ts.map +1 -0
- package/dist/seed.repository.js +3 -0
- package/dist/seeds.d.ts +20 -0
- package/dist/seeds.d.ts.map +1 -0
- package/dist/seeds.js +21 -0
- package/dist/settings/site-settings.repository.d.ts +8 -0
- package/dist/settings/site-settings.repository.d.ts.map +1 -1
- package/dist/site-settings.repository.d.ts +16 -0
- package/dist/site-settings.repository.d.ts.map +1 -0
- package/dist/site-settings.repository.js +3 -0
- package/dist/slug-utils.d.ts +18 -0
- package/dist/slug-utils.d.ts.map +1 -0
- package/dist/slug-utils.js +32 -0
- package/dist/storage.d.ts +46 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +3 -0
- package/dist/transfer/csv.d.ts +34 -0
- package/dist/transfer/csv.d.ts.map +1 -0
- package/dist/transfer/csv.js +135 -0
- package/dist/transfer/flat-seed.d.ts +13 -0
- package/dist/transfer/flat-seed.d.ts.map +1 -0
- package/dist/transfer/flat-seed.js +50 -0
- package/dist/transfer/index.d.ts +7 -0
- package/dist/transfer/index.d.ts.map +1 -0
- package/dist/transfer/index.js +8 -0
- package/dist/transfer/ndjson.d.ts +25 -0
- package/dist/transfer/ndjson.d.ts.map +1 -0
- package/dist/transfer/ndjson.js +62 -0
- package/dist/transfer/row-mapping.d.ts +36 -0
- package/dist/transfer/row-mapping.d.ts.map +1 -0
- package/dist/transfer/row-mapping.js +97 -0
- package/dist/transfer/transfer.constants.d.ts +20 -0
- package/dist/transfer/transfer.constants.d.ts.map +1 -0
- package/dist/transfer/transfer.constants.js +21 -0
- package/dist/transfer/transfer.types.d.ts +46 -0
- package/dist/transfer/transfer.types.d.ts.map +1 -0
- package/dist/transfer/transfer.types.js +6 -0
- package/dist/types.d.ts +243 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/validation.d.ts +50 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +660 -0
- package/dist/webhook-validation.d.ts +3 -0
- package/dist/webhook-validation.d.ts.map +1 -0
- package/dist/webhook-validation.js +6 -0
- package/package.json +11 -6
- package/dist/.tsbuildinfo +0 -1
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Seed, BranchType } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Ordered DROP TABLE statements for a full hard-delete of a seed's tables.
|
|
4
|
+
* Order: junction drafts → junctions → FTS triggers → FTS table → drafts → main table.
|
|
5
|
+
* All statements use IF EXISTS (idempotent).
|
|
6
|
+
*/
|
|
7
|
+
export declare function generateDropTable(seed: Seed): string[];
|
|
8
|
+
/**
|
|
9
|
+
* DROP COLUMN statements for a single branch (by alias).
|
|
10
|
+
* For multi-relation branches: drops the junction tables (no column on parent).
|
|
11
|
+
* For regular branches: drops from main table + drafts table (if allowDrafts).
|
|
12
|
+
* Does NOT include FTS handling — callers must prepend ftsTriggerDrops() and
|
|
13
|
+
* append planFtsRebuild() when the branch is searchable.
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateDropColumn(seed: Seed, alias: string): string[];
|
|
16
|
+
/**
|
|
17
|
+
* RENAME COLUMN statements for a branch alias change.
|
|
18
|
+
* Updates main table + drafts (if allowDrafts).
|
|
19
|
+
* Does NOT handle FTS — callers must rebuild FTS separately (SQLite auto-updates
|
|
20
|
+
* trigger bodies on RENAME but the FTS virtual-table columns keep the old name).
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateRenameColumn(seed: Seed, fromAlias: string, toAlias: string): string[];
|
|
23
|
+
/**
|
|
24
|
+
* Full FTS rebuild: drop triggers + FTS table, then recreate them, then backfill.
|
|
25
|
+
* Returns an empty array if the seed has no searchable branches.
|
|
26
|
+
* The drop steps use IF EXISTS so this is safe to call even if FTS was already dropped.
|
|
27
|
+
*/
|
|
28
|
+
export declare function planFtsRebuild(seed: Seed): string[];
|
|
29
|
+
export interface RetypeColumnPlan {
|
|
30
|
+
statements: string[];
|
|
31
|
+
ftsRebuildNeeded: boolean;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generates statements to change a branch's SQL storage type using the
|
|
35
|
+
* add-new-column / copy / drop-old / rename approach.
|
|
36
|
+
* Includes FTS rebuild statements when the branch is (or becomes) searchable.
|
|
37
|
+
* `updatedSeed` must already reflect the new type on the renamed branch.
|
|
38
|
+
*/
|
|
39
|
+
export declare function planRetypeColumn(seed: Seed, alias: string, newType: BranchType, updatedSeed: Seed): RetypeColumnPlan;
|
|
40
|
+
//# sourceMappingURL=seed-ddl-destructive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-ddl-destructive.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/seed-ddl-destructive.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAU,UAAU,EAAE,MAAM,aAAa,CAAA;AAkC3D;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAgBtD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAgBtE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ7F;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAiBnD;AAED,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,UAAU,EACnB,WAAW,EAAE,IAAI,GAChB,gBAAgB,CAyClB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
import { junctionTableName, generateFtsTable, generateFtsTriggers } from './ddl.js';
|
|
4
|
+
const BRANCH_SQL_TYPE = {
|
|
5
|
+
text: 'TEXT',
|
|
6
|
+
number: 'REAL',
|
|
7
|
+
boolean: 'INTEGER',
|
|
8
|
+
date: 'INTEGER',
|
|
9
|
+
json: 'TEXT',
|
|
10
|
+
richtext: 'TEXT',
|
|
11
|
+
file: 'TEXT',
|
|
12
|
+
tags: 'TEXT',
|
|
13
|
+
relation: 'TEXT',
|
|
14
|
+
repeater: 'TEXT',
|
|
15
|
+
};
|
|
16
|
+
/** Branch types that receive a B-tree index in generateIndexes (used by retype to drop/recreate). */
|
|
17
|
+
const INDEXABLE_TYPES = new Set(['text', 'number', 'date', 'boolean', 'relation']);
|
|
18
|
+
function searchBranches(seed) {
|
|
19
|
+
return seed.branches.filter(b => (b.type === 'text' || b.type === 'richtext') && b.policies?.search !== false);
|
|
20
|
+
}
|
|
21
|
+
function ftsTriggerDrops(slug) {
|
|
22
|
+
return [
|
|
23
|
+
`DROP TRIGGER IF EXISTS fts_${slug}_insert;`,
|
|
24
|
+
`DROP TRIGGER IF EXISTS fts_${slug}_update;`,
|
|
25
|
+
`DROP TRIGGER IF EXISTS fts_${slug}_delete;`,
|
|
26
|
+
`DROP TABLE IF EXISTS fts_${slug};`,
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Ordered DROP TABLE statements for a full hard-delete of a seed's tables.
|
|
31
|
+
* Order: junction drafts → junctions → FTS triggers → FTS table → drafts → main table.
|
|
32
|
+
* All statements use IF EXISTS (idempotent).
|
|
33
|
+
*/
|
|
34
|
+
export function generateDropTable(seed) {
|
|
35
|
+
const stmts = [];
|
|
36
|
+
const { slug } = seed;
|
|
37
|
+
for (const branch of seed.branches) {
|
|
38
|
+
if (branch.type !== 'relation' || branch.multiple !== true)
|
|
39
|
+
continue;
|
|
40
|
+
const jt = junctionTableName(slug, branch.alias);
|
|
41
|
+
stmts.push(`DROP TABLE IF EXISTS ${jt}_drafts;`);
|
|
42
|
+
stmts.push(`DROP TABLE IF EXISTS ${jt};`);
|
|
43
|
+
}
|
|
44
|
+
stmts.push(...ftsTriggerDrops(slug));
|
|
45
|
+
stmts.push(`DROP TABLE IF EXISTS content_${slug}_drafts;`);
|
|
46
|
+
stmts.push(`DROP TABLE IF EXISTS content_${slug};`);
|
|
47
|
+
return stmts;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* DROP COLUMN statements for a single branch (by alias).
|
|
51
|
+
* For multi-relation branches: drops the junction tables (no column on parent).
|
|
52
|
+
* For regular branches: drops from main table + drafts table (if allowDrafts).
|
|
53
|
+
* Does NOT include FTS handling — callers must prepend ftsTriggerDrops() and
|
|
54
|
+
* append planFtsRebuild() when the branch is searchable.
|
|
55
|
+
*/
|
|
56
|
+
export function generateDropColumn(seed, alias) {
|
|
57
|
+
const stmts = [];
|
|
58
|
+
const { slug } = seed;
|
|
59
|
+
const branch = seed.branches.find(b => b.alias === alias);
|
|
60
|
+
if (!branch)
|
|
61
|
+
throw new Error(`Branch '${alias}' not found in seed '${slug}'`);
|
|
62
|
+
if (branch.type === 'relation' && branch.multiple === true) {
|
|
63
|
+
const jt = junctionTableName(slug, alias);
|
|
64
|
+
if (seed.allowDrafts)
|
|
65
|
+
stmts.push(`DROP TABLE IF EXISTS ${jt}_drafts;`);
|
|
66
|
+
stmts.push(`DROP TABLE IF EXISTS ${jt};`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
stmts.push(`ALTER TABLE content_${slug} DROP COLUMN ${alias};`);
|
|
70
|
+
if (seed.allowDrafts)
|
|
71
|
+
stmts.push(`ALTER TABLE content_${slug}_drafts DROP COLUMN ${alias};`);
|
|
72
|
+
}
|
|
73
|
+
return stmts;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* RENAME COLUMN statements for a branch alias change.
|
|
77
|
+
* Updates main table + drafts (if allowDrafts).
|
|
78
|
+
* Does NOT handle FTS — callers must rebuild FTS separately (SQLite auto-updates
|
|
79
|
+
* trigger bodies on RENAME but the FTS virtual-table columns keep the old name).
|
|
80
|
+
*/
|
|
81
|
+
export function generateRenameColumn(seed, fromAlias, toAlias) {
|
|
82
|
+
const stmts = [];
|
|
83
|
+
const { slug } = seed;
|
|
84
|
+
stmts.push(`ALTER TABLE content_${slug} RENAME COLUMN ${fromAlias} TO ${toAlias};`);
|
|
85
|
+
if (seed.allowDrafts) {
|
|
86
|
+
stmts.push(`ALTER TABLE content_${slug}_drafts RENAME COLUMN ${fromAlias} TO ${toAlias};`);
|
|
87
|
+
}
|
|
88
|
+
return stmts;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Full FTS rebuild: drop triggers + FTS table, then recreate them, then backfill.
|
|
92
|
+
* Returns an empty array if the seed has no searchable branches.
|
|
93
|
+
* The drop steps use IF EXISTS so this is safe to call even if FTS was already dropped.
|
|
94
|
+
*/
|
|
95
|
+
export function planFtsRebuild(seed) {
|
|
96
|
+
const rtBranches = searchBranches(seed);
|
|
97
|
+
if (rtBranches.length === 0)
|
|
98
|
+
return [];
|
|
99
|
+
const { slug } = seed;
|
|
100
|
+
const stmts = [...ftsTriggerDrops(slug)];
|
|
101
|
+
const ftsTable = generateFtsTable(seed);
|
|
102
|
+
if (ftsTable)
|
|
103
|
+
stmts.push(ftsTable);
|
|
104
|
+
stmts.push(...generateFtsTriggers(seed));
|
|
105
|
+
const cols = rtBranches.map(b => b.alias);
|
|
106
|
+
stmts.push(`INSERT INTO fts_${slug}(entry_id, ${cols.join(', ')}) SELECT id, ${cols.join(', ')} FROM content_${slug};`);
|
|
107
|
+
return stmts;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Generates statements to change a branch's SQL storage type using the
|
|
111
|
+
* add-new-column / copy / drop-old / rename approach.
|
|
112
|
+
* Includes FTS rebuild statements when the branch is (or becomes) searchable.
|
|
113
|
+
* `updatedSeed` must already reflect the new type on the renamed branch.
|
|
114
|
+
*/
|
|
115
|
+
export function planRetypeColumn(seed, alias, newType, updatedSeed) {
|
|
116
|
+
const branch = seed.branches.find(b => b.alias === alias);
|
|
117
|
+
if (!branch)
|
|
118
|
+
throw new Error(`Branch '${alias}' not found in seed '${seed.slug}'`);
|
|
119
|
+
const { slug } = seed;
|
|
120
|
+
const newSqlType = BRANCH_SQL_TYPE[newType];
|
|
121
|
+
const tmpAlias = `${alias}_migrate`;
|
|
122
|
+
const stmts = [];
|
|
123
|
+
// Always drop FTS first to avoid "column referenced in trigger" errors on DROP COLUMN.
|
|
124
|
+
stmts.push(...ftsTriggerDrops(slug));
|
|
125
|
+
// Drop the branch index if it exists on the old column (required before DROP COLUMN).
|
|
126
|
+
if (INDEXABLE_TYPES.has(branch.type) && branch.policies?.filter !== false) {
|
|
127
|
+
stmts.push(`DROP INDEX IF EXISTS idx_${slug}_${alias};`);
|
|
128
|
+
}
|
|
129
|
+
// Main table: add migration column, copy data, drop old, rename.
|
|
130
|
+
stmts.push(`ALTER TABLE content_${slug} ADD COLUMN ${tmpAlias} ${newSqlType};`);
|
|
131
|
+
stmts.push(`UPDATE content_${slug} SET ${tmpAlias} = CAST(${alias} AS ${newSqlType});`);
|
|
132
|
+
stmts.push(`ALTER TABLE content_${slug} DROP COLUMN ${alias};`);
|
|
133
|
+
stmts.push(`ALTER TABLE content_${slug} RENAME COLUMN ${tmpAlias} TO ${alias};`);
|
|
134
|
+
// Recreate index for the renamed column if the new type warrants it.
|
|
135
|
+
if (INDEXABLE_TYPES.has(newType) && branch.policies?.filter !== false) {
|
|
136
|
+
stmts.push(`CREATE INDEX IF NOT EXISTS idx_${slug}_${alias} ON content_${slug}(${alias});`);
|
|
137
|
+
}
|
|
138
|
+
// Drafts table (no indexes to worry about).
|
|
139
|
+
if (seed.allowDrafts) {
|
|
140
|
+
stmts.push(`ALTER TABLE content_${slug}_drafts ADD COLUMN ${tmpAlias} ${newSqlType};`);
|
|
141
|
+
stmts.push(`UPDATE content_${slug}_drafts SET ${tmpAlias} = CAST(${alias} AS ${newSqlType});`);
|
|
142
|
+
stmts.push(`ALTER TABLE content_${slug}_drafts DROP COLUMN ${alias};`);
|
|
143
|
+
stmts.push(`ALTER TABLE content_${slug}_drafts RENAME COLUMN ${tmpAlias} TO ${alias};`);
|
|
144
|
+
}
|
|
145
|
+
// Rebuild FTS if the seed has searchable branches in the updated definition.
|
|
146
|
+
const rebuild = planFtsRebuild(updatedSeed);
|
|
147
|
+
stmts.push(...rebuild);
|
|
148
|
+
return { statements: stmts, ftsRebuildNeeded: rebuild.length > 0 };
|
|
149
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { Seed } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Full create-from-scratch statement set for a seed. Mirrors the CLI's buildStatements.
|
|
4
|
+
* Order: parent table → indexes → draft table → FTS table → FTS triggers →
|
|
5
|
+
* per multi-relation: junction table → junction indexes → junction draft table.
|
|
6
|
+
* Callers that create several seeds must order seeds with sortSeedsByDependencies
|
|
7
|
+
* first so relation FK targets exist.
|
|
8
|
+
*/
|
|
9
|
+
export declare function planCreateSeed(seed: Seed): string[];
|
|
10
|
+
export interface ExtendPlan {
|
|
11
|
+
statements: string[];
|
|
12
|
+
ftsRebuildNeeded: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Additive extension: given the columns that already exist on content_{slug}
|
|
16
|
+
* (from PRAGMA table_info, passed in by the caller), return ONLY the statements
|
|
17
|
+
* needed to add new branches — ADD COLUMN + indexes, plus junction tables for
|
|
18
|
+
* new multi-relation branches. Never drops or renames.
|
|
19
|
+
*
|
|
20
|
+
* FTS: SQLite cannot ALTER an fts5 table's columns. If a new text/richtext
|
|
21
|
+
* searchable branch was added, ftsRebuildNeeded=true signals the caller
|
|
22
|
+
* (sprint 03) to handle it — no DROP is emitted.
|
|
23
|
+
*
|
|
24
|
+
* Draft tables: pass `existingDraftColumns` (PRAGMA table_info on content_{slug}_drafts) to have the
|
|
25
|
+
* `live_snapshot_at` system column added retroactively; omit it to skip that check entirely.
|
|
26
|
+
*/
|
|
27
|
+
export declare function planExtendSeed(seed: Seed, existingColumns: Set<string>, existingDraftColumns?: Set<string> | null): ExtendPlan;
|
|
28
|
+
/**
|
|
29
|
+
* Destructive FTS rebuild (sprint 06). SQLite cannot ALTER an fts5 table's
|
|
30
|
+
* columns, so when a searchable branch is added, renamed, retyped, or dropped
|
|
31
|
+
* the only correct fix is to drop and recreate the `fts_{slug}` virtual table
|
|
32
|
+
* (and its insert/update/delete triggers), then backfill from `content_{slug}`.
|
|
33
|
+
*
|
|
34
|
+
* Returns an empty array when the seed has no searchable branches — in that
|
|
35
|
+
* case the caller should instead drop any leftover FTS table via
|
|
36
|
+
* generateDropTable's FTS statements. The returned statements are destructive
|
|
37
|
+
* and must run through ISchemaMutator.execDestructive, never execDdl.
|
|
38
|
+
*
|
|
39
|
+
* Order: drop triggers → drop fts table → recreate table → recreate triggers →
|
|
40
|
+
* backfill existing rows.
|
|
41
|
+
*/
|
|
42
|
+
export declare function planFtsRebuild(seed: Seed): string[];
|
|
43
|
+
//# sourceMappingURL=seed-ddl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-ddl.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/seed-ddl.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAgBvC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAanD;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,EAAE,CAAA;IACpB,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,EAC5B,oBAAoB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GACxC,UAAU,CAmCZ;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CA0BnD"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
import { generateCreateTable, generateDraftTable, generateIndexes, generateFtsTable, generateFtsTriggers, generateAddColumn, generateAddDraftSnapshotColumn, generateJunctionTable, generateJunctionIndexes, generateJunctionDraftTable, generateEnableSoftDelete, indexableSearchBranches, } from './ddl.js';
|
|
4
|
+
/**
|
|
5
|
+
* Full create-from-scratch statement set for a seed. Mirrors the CLI's buildStatements.
|
|
6
|
+
* Order: parent table → indexes → draft table → FTS table → FTS triggers →
|
|
7
|
+
* per multi-relation: junction table → junction indexes → junction draft table.
|
|
8
|
+
* Callers that create several seeds must order seeds with sortSeedsByDependencies
|
|
9
|
+
* first so relation FK targets exist.
|
|
10
|
+
*/
|
|
11
|
+
export function planCreateSeed(seed) {
|
|
12
|
+
const stmts = [generateCreateTable(seed), ...generateIndexes(seed)];
|
|
13
|
+
const draft = generateDraftTable(seed);
|
|
14
|
+
if (draft)
|
|
15
|
+
stmts.push(draft);
|
|
16
|
+
const fts = generateFtsTable(seed);
|
|
17
|
+
if (fts)
|
|
18
|
+
stmts.push(fts, ...generateFtsTriggers(seed));
|
|
19
|
+
for (const branch of seed.branches) {
|
|
20
|
+
if (branch.type !== 'relation' || branch.multiple !== true)
|
|
21
|
+
continue;
|
|
22
|
+
stmts.push(generateJunctionTable(seed, branch), ...generateJunctionIndexes(seed, branch));
|
|
23
|
+
const dj = generateJunctionDraftTable(seed, branch);
|
|
24
|
+
if (dj)
|
|
25
|
+
stmts.push(dj);
|
|
26
|
+
}
|
|
27
|
+
return stmts;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Additive extension: given the columns that already exist on content_{slug}
|
|
31
|
+
* (from PRAGMA table_info, passed in by the caller), return ONLY the statements
|
|
32
|
+
* needed to add new branches — ADD COLUMN + indexes, plus junction tables for
|
|
33
|
+
* new multi-relation branches. Never drops or renames.
|
|
34
|
+
*
|
|
35
|
+
* FTS: SQLite cannot ALTER an fts5 table's columns. If a new text/richtext
|
|
36
|
+
* searchable branch was added, ftsRebuildNeeded=true signals the caller
|
|
37
|
+
* (sprint 03) to handle it — no DROP is emitted.
|
|
38
|
+
*
|
|
39
|
+
* Draft tables: pass `existingDraftColumns` (PRAGMA table_info on content_{slug}_drafts) to have the
|
|
40
|
+
* `live_snapshot_at` system column added retroactively; omit it to skip that check entirely.
|
|
41
|
+
*/
|
|
42
|
+
export function planExtendSeed(seed, existingColumns, existingDraftColumns) {
|
|
43
|
+
const statements = [];
|
|
44
|
+
let ftsRebuildNeeded = false;
|
|
45
|
+
for (const branch of seed.branches) {
|
|
46
|
+
if (branch.type === 'relation' && branch.multiple === true) {
|
|
47
|
+
// junction table is CREATE IF NOT EXISTS — safe to re-emit
|
|
48
|
+
statements.push(generateJunctionTable(seed, branch), ...generateJunctionIndexes(seed, branch));
|
|
49
|
+
const dj = generateJunctionDraftTable(seed, branch);
|
|
50
|
+
if (dj)
|
|
51
|
+
statements.push(dj);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (existingColumns.has(branch.alias))
|
|
55
|
+
continue;
|
|
56
|
+
statements.push(generateAddColumn(seed, branch));
|
|
57
|
+
if ((branch.type === 'text' || branch.type === 'richtext') && branch.policies?.search !== false) {
|
|
58
|
+
ftsRebuildNeeded = true;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// System column, not a branch: the branch loop above can never emit it.
|
|
62
|
+
if (seed.softDelete && !existingColumns.has('deleted_at')) {
|
|
63
|
+
statements.push(...generateEnableSoftDelete(seed));
|
|
64
|
+
}
|
|
65
|
+
// Draft-table system column. Emitted only when the caller actually introspected
|
|
66
|
+
// content_{slug}_drafts: `undefined` means "not introspected" and `null` means "table absent",
|
|
67
|
+
// and in both cases emitting a non-idempotent ADD COLUMN would abort the caller's whole DDL batch.
|
|
68
|
+
if (seed.allowDrafts &&
|
|
69
|
+
existingDraftColumns != null &&
|
|
70
|
+
!existingDraftColumns.has('live_snapshot_at')) {
|
|
71
|
+
statements.push(generateAddDraftSnapshotColumn(seed));
|
|
72
|
+
}
|
|
73
|
+
// CREATE INDEX IF NOT EXISTS — idempotent, safe to re-run
|
|
74
|
+
statements.push(...generateIndexes(seed));
|
|
75
|
+
return { statements, ftsRebuildNeeded };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Destructive FTS rebuild (sprint 06). SQLite cannot ALTER an fts5 table's
|
|
79
|
+
* columns, so when a searchable branch is added, renamed, retyped, or dropped
|
|
80
|
+
* the only correct fix is to drop and recreate the `fts_{slug}` virtual table
|
|
81
|
+
* (and its insert/update/delete triggers), then backfill from `content_{slug}`.
|
|
82
|
+
*
|
|
83
|
+
* Returns an empty array when the seed has no searchable branches — in that
|
|
84
|
+
* case the caller should instead drop any leftover FTS table via
|
|
85
|
+
* generateDropTable's FTS statements. The returned statements are destructive
|
|
86
|
+
* and must run through ISchemaMutator.execDestructive, never execDdl.
|
|
87
|
+
*
|
|
88
|
+
* Order: drop triggers → drop fts table → recreate table → recreate triggers →
|
|
89
|
+
* backfill existing rows.
|
|
90
|
+
*/
|
|
91
|
+
export function planFtsRebuild(seed) {
|
|
92
|
+
const branches = indexableSearchBranches(seed);
|
|
93
|
+
if (branches.length === 0)
|
|
94
|
+
return [];
|
|
95
|
+
const slug = seed.slug;
|
|
96
|
+
const ftsTable = `fts_${slug}`;
|
|
97
|
+
const contentTable = `content_${slug}`;
|
|
98
|
+
const cols = branches.map(b => b.alias);
|
|
99
|
+
const ftsTableDdl = generateFtsTable(seed);
|
|
100
|
+
const triggers = generateFtsTriggers(seed);
|
|
101
|
+
// generateFtsTable/Triggers return non-null here (branches.length > 0 checked).
|
|
102
|
+
if (!ftsTableDdl)
|
|
103
|
+
return [];
|
|
104
|
+
const ftsColList = ['entry_id', ...cols].join(', ');
|
|
105
|
+
const selectList = ['id', ...cols].join(', ');
|
|
106
|
+
return [
|
|
107
|
+
`DROP TRIGGER IF EXISTS fts_${slug}_insert;`,
|
|
108
|
+
`DROP TRIGGER IF EXISTS fts_${slug}_update;`,
|
|
109
|
+
`DROP TRIGGER IF EXISTS fts_${slug}_delete;`,
|
|
110
|
+
`DROP TABLE IF EXISTS ${ftsTable};`,
|
|
111
|
+
ftsTableDdl,
|
|
112
|
+
...triggers,
|
|
113
|
+
`INSERT INTO ${ftsTable}(${ftsColList}) SELECT ${selectList} FROM ${contentTable};`,
|
|
114
|
+
];
|
|
115
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Seed } from '../types.js';
|
|
2
|
+
/** Blocks writes from requests that loaded a seed immediately before its purge began. */
|
|
3
|
+
export declare function generateSeedPurgeGuards(seed: Seed): {
|
|
4
|
+
create: string[];
|
|
5
|
+
drop: string[];
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=seed-purge-guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed-purge-guards.d.ts","sourceRoot":"","sources":["../../../src/engine/ddl/seed-purge-guards.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC,yFAAyF;AACzF,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAcxF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
/** Blocks writes from requests that loaded a seed immediately before its purge began. */
|
|
4
|
+
export function generateSeedPurgeGuards(seed) {
|
|
5
|
+
if (!/^[a-z0-9_]+$/.test(seed.slug))
|
|
6
|
+
throw new Error(`Unsafe seed slug: ${seed.slug}`);
|
|
7
|
+
const tables = [`content_${seed.slug}`, ...(seed.allowDrafts ? [`content_${seed.slug}_drafts`] : [])];
|
|
8
|
+
const operations = ['INSERT', 'UPDATE', 'DELETE'];
|
|
9
|
+
const create = [];
|
|
10
|
+
const drop = [];
|
|
11
|
+
for (const table of tables) {
|
|
12
|
+
for (const operation of operations) {
|
|
13
|
+
const name = `purge_guard_${table}_${operation.toLowerCase()}`;
|
|
14
|
+
create.push(`CREATE TRIGGER ${name} BEFORE ${operation} ON ${table} BEGIN SELECT RAISE(ABORT, 'seed_purge_in_progress'); END;`);
|
|
15
|
+
drop.push(`DROP TRIGGER IF EXISTS ${name};`);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return { create, drop };
|
|
19
|
+
}
|
package/dist/engine/engine.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export * from './ddl.js';
|
|
2
|
-
export * from './query.js';
|
|
3
|
-
export * from './serialize.js';
|
|
1
|
+
export * from './ddl/ddl.js';
|
|
2
|
+
export * from './query/query.js';
|
|
3
|
+
export * from './query/serialize.js';
|
|
4
|
+
export * from './query/active-clause.js';
|
|
4
5
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine/engine.ts"],"names":[],"mappings":"AACA,cAAc,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/engine/engine.ts"],"names":[],"mappings":"AACA,cAAc,cAAc,CAAA;AAC5B,cAAc,kBAAkB,CAAA;AAChC,cAAc,sBAAsB,CAAA;AACpC,cAAc,0BAA0B,CAAA"}
|
package/dist/engine/engine.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
export * from './ddl.js';
|
|
3
|
-
export * from './query.js';
|
|
4
|
-
export * from './serialize.js';
|
|
2
|
+
export * from './ddl/ddl.js';
|
|
3
|
+
export * from './query/query.js';
|
|
4
|
+
export * from './query/serialize.js';
|
|
5
|
+
export * from './query/active-clause.js';
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module engine/introspection
|
|
3
|
+
* Reads live schema state out of D1 through an INJECTED executor.
|
|
4
|
+
*
|
|
5
|
+
* Executor-agnostic on purpose: the CLI reaches D1 through a synchronous shell/SQLite path
|
|
6
|
+
* (`queryD1`) and the Worker through its `D1Database` binding, and neither tier may import the
|
|
7
|
+
* other (`graphify path "createBeechApp" "queryD1"` must keep returning no path). `@beechcms/core`
|
|
8
|
+
* owns the STATEMENTS and the SHAPES; the caller owns the connection.
|
|
9
|
+
*
|
|
10
|
+
* Read-only by contract: every statement here is a `PRAGMA` or a `SELECT`. Schema mutation stays
|
|
11
|
+
* the exclusive business of the Botanical Engine's DDL path (`engine/seed-ddl.ts`).
|
|
12
|
+
*/
|
|
13
|
+
import type { Seed } from '../types.js';
|
|
14
|
+
/**
|
|
15
|
+
* The one capability the introspection primitive needs from a database connection.
|
|
16
|
+
*
|
|
17
|
+
* Implementations MUST: execute the statement as-is, return one object per row with column names
|
|
18
|
+
* as keys, and reject/throw on failure. They MUST NOT cache, batch, rewrite or retry — a stale
|
|
19
|
+
* answer here becomes a wrong fingerprint, which becomes a false "your types are stale" error in
|
|
20
|
+
* someone else's production client.
|
|
21
|
+
*/
|
|
22
|
+
export interface SchemaQueryExecutor {
|
|
23
|
+
all<T extends Record<string, unknown>>(sql: string): Promise<T[]>;
|
|
24
|
+
}
|
|
25
|
+
/** Thrown when live state cannot be read or cannot be trusted. */
|
|
26
|
+
export declare class IntrospectionError extends Error {
|
|
27
|
+
readonly cause?: unknown | undefined;
|
|
28
|
+
constructor(message: string, cause?: unknown | undefined);
|
|
29
|
+
}
|
|
30
|
+
/** One physical column, as SQLite reports it. */
|
|
31
|
+
export interface LiveColumn {
|
|
32
|
+
name: string;
|
|
33
|
+
/** Declared storage type, upper-cased (`TEXT` | `INTEGER` | `REAL` | …). */
|
|
34
|
+
sqlType: string;
|
|
35
|
+
notNull: boolean;
|
|
36
|
+
isPk: boolean;
|
|
37
|
+
/** Declared DEFAULT expression verbatim, or null. */
|
|
38
|
+
defaultValue: string | null;
|
|
39
|
+
}
|
|
40
|
+
/** One foreign-key constraint on a physical table. */
|
|
41
|
+
export interface LiveForeignKey {
|
|
42
|
+
/** Local column carrying the reference. */
|
|
43
|
+
column: string;
|
|
44
|
+
/** Referenced table, e.g. `content_team`. */
|
|
45
|
+
targetTable: string;
|
|
46
|
+
/** Referenced column, e.g. `id`. */
|
|
47
|
+
targetColumn: string;
|
|
48
|
+
/** Upper-cased, e.g. `SET NULL`. */
|
|
49
|
+
onDelete: string;
|
|
50
|
+
/** Upper-cased, e.g. `NO ACTION`. */
|
|
51
|
+
onUpdate: string;
|
|
52
|
+
}
|
|
53
|
+
/** One index on a physical table. SQLite's implicit `sqlite_autoindex_*` entries are excluded. */
|
|
54
|
+
export interface LiveIndex {
|
|
55
|
+
name: string;
|
|
56
|
+
unique: boolean;
|
|
57
|
+
}
|
|
58
|
+
/** The physical state of one table. `exists: false` means SQLite reports no such table. */
|
|
59
|
+
export interface LiveTable {
|
|
60
|
+
name: string;
|
|
61
|
+
exists: boolean;
|
|
62
|
+
/** Physical order, as returned by `PRAGMA table_info` (cid order). */
|
|
63
|
+
columns: LiveColumn[];
|
|
64
|
+
/** Sorted by `column`, then `targetTable`, for deterministic output. */
|
|
65
|
+
foreignKeys: LiveForeignKey[];
|
|
66
|
+
/** Sorted by `name`. */
|
|
67
|
+
indexes: LiveIndex[];
|
|
68
|
+
}
|
|
69
|
+
/** The physical state of a set of tables. `tables` is sorted by name. */
|
|
70
|
+
export interface LiveSchema {
|
|
71
|
+
tables: LiveTable[];
|
|
72
|
+
}
|
|
73
|
+
/** Returns `name` unchanged when it is a safe SQL identifier; throws otherwise. */
|
|
74
|
+
export declare function assertSafeIdentifier(name: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* Physical state of one table. A table SQLite does not know returns `{ exists: false }` with empty
|
|
77
|
+
* lists rather than throwing: "missing" is a legitimate diff outcome, not an error.
|
|
78
|
+
*
|
|
79
|
+
* `PRAGMA table_info` answers an unknown table with zero rows on the SQLite path and raises on some
|
|
80
|
+
* wrangler paths, so both outcomes collapse to the same result.
|
|
81
|
+
*/
|
|
82
|
+
export declare function introspectTable(executor: SchemaQueryExecutor, table: string): Promise<LiveTable>;
|
|
83
|
+
/**
|
|
84
|
+
* Names of the physical tables SQLite holds, optionally restricted to a `LIKE` prefix
|
|
85
|
+
* (e.g. `content_`). Sorted, `sqlite_*` internals excluded.
|
|
86
|
+
*/
|
|
87
|
+
export declare function listTables(executor: SchemaQueryExecutor, prefix?: string): Promise<string[]>;
|
|
88
|
+
/**
|
|
89
|
+
* Physical state of several tables at once. With no explicit list, every `content_*` table is
|
|
90
|
+
* introspected — the set a schema export or a drift check cares about.
|
|
91
|
+
*/
|
|
92
|
+
export declare function introspectSchema(executor: SchemaQueryExecutor, tables?: string[]): Promise<LiveSchema>;
|
|
93
|
+
/**
|
|
94
|
+
* The DECLARED schema: every active seed definition, read live from D1.
|
|
95
|
+
*
|
|
96
|
+
* This — not `beech.schema.ts` — is the source of truth for generated types and for the schema
|
|
97
|
+
* fingerprint (feature brief, business rule 1). The manifest file is a desired-state artifact and
|
|
98
|
+
* may legitimately be ahead of, or behind, what is deployed.
|
|
99
|
+
*/
|
|
100
|
+
export declare function introspectSeedDefinitions(executor: SchemaQueryExecutor): Promise<Seed[]>;
|
|
101
|
+
//# sourceMappingURL=introspection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspection.d.ts","sourceRoot":"","sources":["../../../src/engine/introspection/introspection.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC;;;;;;;GAOG;AACH,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAA;CAClE;AAED,kEAAkE;AAClE,qBAAa,kBAAmB,SAAQ,KAAK;IACd,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO;gBAAzC,OAAO,EAAE,MAAM,EAAW,KAAK,CAAC,EAAE,OAAO,YAAA;CAItD;AAED,iDAAiD;AACjD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,OAAO,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;IACb,qDAAqD;IACrD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAA;IACd,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAA;IACnB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAA;IACpB,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,kGAAkG;AAClG,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,2FAA2F;AAC3F,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,OAAO,EAAE,UAAU,EAAE,CAAA;IACrB,wEAAwE;IACxE,WAAW,EAAE,cAAc,EAAE,CAAA;IAC7B,wBAAwB;IACxB,OAAO,EAAE,SAAS,EAAE,CAAA;CACrB;AAED,yEAAyE;AACzE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,EAAE,CAAA;CACpB;AA6CD,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOzD;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,SAAS,CAAC,CAgDpB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,EAAE,CAAC,CAOnB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,mBAAmB,EAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,UAAU,CAAC,CAUrB;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC7C,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,EAAE,CAAC,CAoBjB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Copyright (c) 2024–2026 Flavio De Musso
|
|
3
|
+
/** Thrown when live state cannot be read or cannot be trusted. */
|
|
4
|
+
export class IntrospectionError extends Error {
|
|
5
|
+
cause;
|
|
6
|
+
constructor(message, cause) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.cause = cause;
|
|
9
|
+
this.name = 'IntrospectionError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* SQLite identifiers cannot be bound as parameters, so every table name reaching a PRAGMA is
|
|
14
|
+
* interpolated — and therefore must be proven safe first. Table names in this system are always
|
|
15
|
+
* `content_{slug}` / `rel_{slug}_{alias}` / a structural table, all of which match this pattern.
|
|
16
|
+
*/
|
|
17
|
+
const SAFE_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
18
|
+
/** Returns `name` unchanged when it is a safe SQL identifier; throws otherwise. */
|
|
19
|
+
export function assertSafeIdentifier(name) {
|
|
20
|
+
if (!SAFE_IDENTIFIER.test(name)) {
|
|
21
|
+
throw new IntrospectionError(`Refusing to introspect '${name}': not a plain SQL identifier. Table names are never user input in BeechCMS.`);
|
|
22
|
+
}
|
|
23
|
+
return name;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Physical state of one table. A table SQLite does not know returns `{ exists: false }` with empty
|
|
27
|
+
* lists rather than throwing: "missing" is a legitimate diff outcome, not an error.
|
|
28
|
+
*
|
|
29
|
+
* `PRAGMA table_info` answers an unknown table with zero rows on the SQLite path and raises on some
|
|
30
|
+
* wrangler paths, so both outcomes collapse to the same result.
|
|
31
|
+
*/
|
|
32
|
+
export async function introspectTable(executor, table) {
|
|
33
|
+
const name = assertSafeIdentifier(table);
|
|
34
|
+
const empty = { name, exists: false, columns: [], foreignKeys: [], indexes: [] };
|
|
35
|
+
let info;
|
|
36
|
+
try {
|
|
37
|
+
info = await executor.all(`PRAGMA table_info(${name})`);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return empty;
|
|
41
|
+
}
|
|
42
|
+
if (info.length === 0)
|
|
43
|
+
return empty;
|
|
44
|
+
const columns = info.map(row => ({
|
|
45
|
+
name: row.name,
|
|
46
|
+
sqlType: String(row.type ?? '').toUpperCase(),
|
|
47
|
+
notNull: row.notnull === 1,
|
|
48
|
+
isPk: row.pk > 0,
|
|
49
|
+
defaultValue: row.dflt_value ?? null,
|
|
50
|
+
}));
|
|
51
|
+
let fkRows = [];
|
|
52
|
+
let indexRows = [];
|
|
53
|
+
try {
|
|
54
|
+
fkRows = await executor.all(`PRAGMA foreign_key_list(${name})`);
|
|
55
|
+
indexRows = await executor.all(`PRAGMA index_list(${name})`);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// A table with neither FKs nor indexes answers with zero rows on some drivers and raises on
|
|
59
|
+
// others; an unreadable constraint list must not hide the column list we already have.
|
|
60
|
+
}
|
|
61
|
+
const foreignKeys = fkRows
|
|
62
|
+
.map(row => ({
|
|
63
|
+
column: row.from,
|
|
64
|
+
targetTable: row.table,
|
|
65
|
+
targetColumn: row.to ?? 'id',
|
|
66
|
+
onDelete: String(row.on_delete ?? '').toUpperCase(),
|
|
67
|
+
onUpdate: String(row.on_update ?? '').toUpperCase(),
|
|
68
|
+
}))
|
|
69
|
+
.sort((a, b) => a.column.localeCompare(b.column) || a.targetTable.localeCompare(b.targetTable));
|
|
70
|
+
const indexes = indexRows
|
|
71
|
+
// Implicit indexes SQLite mints for UNIQUE/PK are not schema an author declared, and their
|
|
72
|
+
// names are not stable across environments.
|
|
73
|
+
.filter(row => !row.name.startsWith('sqlite_autoindex_'))
|
|
74
|
+
.map(row => ({ name: row.name, unique: row.unique === 1 }))
|
|
75
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
76
|
+
return { name, exists: true, columns, foreignKeys, indexes };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Names of the physical tables SQLite holds, optionally restricted to a `LIKE` prefix
|
|
80
|
+
* (e.g. `content_`). Sorted, `sqlite_*` internals excluded.
|
|
81
|
+
*/
|
|
82
|
+
export async function listTables(executor, prefix) {
|
|
83
|
+
if (prefix !== undefined)
|
|
84
|
+
assertSafeIdentifier(`${prefix}x`);
|
|
85
|
+
const filter = prefix ? ` AND name LIKE '${prefix}%'` : '';
|
|
86
|
+
const rows = await executor.all(`SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'${filter} ORDER BY name ASC`);
|
|
87
|
+
return rows.map(row => row.name);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Physical state of several tables at once. With no explicit list, every `content_*` table is
|
|
91
|
+
* introspected — the set a schema export or a drift check cares about.
|
|
92
|
+
*/
|
|
93
|
+
export async function introspectSchema(executor, tables) {
|
|
94
|
+
const names = tables ?? await listTables(executor, 'content_');
|
|
95
|
+
const sorted = [...names].sort((a, b) => a.localeCompare(b));
|
|
96
|
+
const result = [];
|
|
97
|
+
// Sequential on purpose: the CLI executor is a synchronous shell/SQLite call behind a Promise,
|
|
98
|
+
// and D1 rejects unbounded concurrent statements from one request.
|
|
99
|
+
for (const name of sorted) {
|
|
100
|
+
result.push(await introspectTable(executor, name));
|
|
101
|
+
}
|
|
102
|
+
return { tables: result };
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The DECLARED schema: every active seed definition, read live from D1.
|
|
106
|
+
*
|
|
107
|
+
* This — not `beech.schema.ts` — is the source of truth for generated types and for the schema
|
|
108
|
+
* fingerprint (feature brief, business rule 1). The manifest file is a desired-state artifact and
|
|
109
|
+
* may legitimately be ahead of, or behind, what is deployed.
|
|
110
|
+
*/
|
|
111
|
+
export async function introspectSeedDefinitions(executor) {
|
|
112
|
+
let rows;
|
|
113
|
+
try {
|
|
114
|
+
rows = await executor.all(`SELECT slug, definition FROM seeds WHERE status = 'active' ORDER BY slug ASC`);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
throw new IntrospectionError('Failed to read the `seeds` table from D1.', error);
|
|
118
|
+
}
|
|
119
|
+
return rows.map(row => {
|
|
120
|
+
try {
|
|
121
|
+
return JSON.parse(row.definition);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
throw new IntrospectionError(`Seed '${row.slug}' holds a definition that is not valid JSON; D1 state is corrupt.`, error);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|