@happyvertical/smrt-core 0.51.31 → 0.51.33
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/build-knowledge.md +13 -0
- package/dist/__tests__/fixtures/collection-coverage-fixtures.d.ts +8 -0
- package/dist/__tests__/fixtures/inheritance-resolver-fixtures.d.ts +9 -0
- package/dist/__tests__/fixtures/inheritance-test-classes.d.ts +5 -0
- package/dist/__tests__/fixtures/object-ai-memory-fixtures.d.ts +10 -0
- package/dist/__typechecks__/collection-read-plan.d.ts +2 -2
- package/dist/adapters/ai-usage.d.ts +5 -2
- package/dist/adapters/cost-rates.d.ts +1 -1
- package/dist/adapters/metrics.d.ts +7 -1
- package/dist/adapters/pubsub.d.ts +7 -1
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +2 -1
- package/dist/cascade.d.ts +69 -3
- package/dist/change-feed-authz.d.ts +85 -2
- package/dist/change-feed.d.ts +133 -2
- package/dist/change-signals.d.ts +66 -1
- package/dist/child-accessors.d.ts +39 -1
- package/dist/class.d.ts +17 -8
- package/dist/class.d.ts.map +1 -1
- package/dist/class.js +22 -0
- package/dist/class.js.map +1 -1
- package/dist/collection-cache.d.ts +47 -1
- package/dist/collection-read-plan.d.ts +3 -3
- package/dist/collection.d.ts +4 -3
- package/dist/config.d.ts +15 -6
- package/dist/consumer-plugin/index.d.ts +7 -3
- package/dist/consumer-plugin/index.d.ts.map +1 -1
- package/dist/consumer-plugin/index.js +2 -0
- package/dist/consumer-plugin/index.js.map +1 -1
- package/dist/data-query.d.ts +12 -1
- package/dist/database.d.ts +10 -2
- package/dist/decisions.d.ts +24 -2
- package/dist/decisions.d.ts.map +1 -1
- package/dist/decisions.js +71 -1
- package/dist/decisions.js.map +1 -1
- package/dist/decorators/index.d.ts +11 -5
- package/dist/dispatch/bus.d.ts +27 -2
- package/dist/dispatch/collections/DispatchSubscriptions.d.ts +7 -2
- package/dist/dispatch/collections/Dispatches.d.ts +8 -3
- package/dist/dispatch/models/Dispatch.d.ts +7 -1
- package/dist/dispatch/types.d.ts +7 -2
- package/dist/embedded-write-queue.d.ts +1 -1
- package/dist/embeddings/provider.d.ts +8 -1
- package/dist/embeddings/storage.d.ts +8 -2
- package/dist/filesystem-loader.d.ts +16 -1
- package/dist/generators/changes-route.d.ts +34 -1
- package/dist/generators/custom-action.d.ts +10 -2
- package/dist/generators/events-route.d.ts +41 -4
- package/dist/generators/mcp-runtime-template.d.ts +13 -2
- package/dist/generators/mcp.d.ts +6 -1
- package/dist/generators/rest.d.ts +10 -5
- package/dist/generators/tool-schema.d.ts +1 -1
- package/dist/hierarchical.d.ts +37 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/interceptors.d.ts +45 -1
- package/dist/junction.d.ts +24 -0
- package/dist/knowledge-config.d.ts +1 -1
- package/dist/knowledge-discovery.d.ts +2 -25
- package/dist/knowledge-discovery.d.ts.map +1 -1
- package/dist/knowledge-discovery.js +1 -53
- package/dist/knowledge-graph.d.ts +2 -94
- package/dist/knowledge-graph.d.ts.map +1 -1
- package/dist/knowledge-graph.js +1 -267
- package/dist/knowledge.d.ts +4 -23
- package/dist/knowledge.d.ts.map +1 -1
- package/dist/knowledge.js +3 -52
- package/dist/knowledge.js.map +1 -1
- package/dist/learning/memory.d.ts +21 -1
- package/dist/manifest/generator.d.ts +5 -1
- package/dist/manifest/index.d.ts +5 -1
- package/dist/manifest/manager.d.ts +1 -1
- package/dist/manifest/manifest-loader.d.ts +24 -2
- package/dist/manifest/sources/composite.d.ts +17 -1
- package/dist/manifest/sources/embedded.d.ts +10 -1
- package/dist/manifest/sources/explicit-paths.d.ts +13 -1
- package/dist/manifest/sources/fallback.d.ts +15 -1
- package/dist/manifest/sources/local-test.d.ts +10 -1
- package/dist/manifest/sources/static.d.ts +12 -1
- package/dist/manifest/sources/test.d.ts +9 -1
- package/dist/manifest/sources/types.d.ts +7 -1
- package/dist/manifest/static-manifest.d.ts +6 -1
- package/dist/manifest/static-manifest.js +1 -1
- package/dist/manifest/static-manifest.js.map +1 -1
- package/dist/manifest/store.d.ts +22 -3
- package/dist/manifest/store.js +1 -1
- package/dist/manifest.json +1 -1
- package/dist/migrations/backfill-tracker.d.ts +15 -1
- package/dist/migrations/differ.d.ts +8 -2
- package/dist/migrations/framework-base-tables.d.ts +57 -2
- package/dist/migrations/generator.d.ts +8 -2
- package/dist/migrations/integer-width.d.ts +10 -2
- package/dist/migrations/minor-units.d.ts +40 -1
- package/dist/migrations/null-equal-indexes.d.ts +3 -2
- package/dist/migrations/orchestrate.d.ts +15 -3
- package/dist/migrations/sqlite-rebuild.d.ts +67 -2
- package/dist/migrations/tracker.d.ts +9 -3
- package/dist/migrations/types.d.ts +7 -2
- package/dist/object.d.ts +7 -6
- package/dist/object.d.ts.map +1 -1
- package/dist/object.js +6 -17
- package/dist/object.js.map +1 -1
- package/dist/polymorphic-association.d.ts +44 -1
- package/dist/postgres-permissions.d.ts +1 -1
- package/dist/prebuild/index.d.ts +5 -1
- package/dist/query-bounds.d.ts +26 -0
- package/dist/registry/cache-config.d.ts +10 -1
- package/dist/registry/class-registration.d.ts +10 -2
- package/dist/registry/collection-resolution.d.ts +1 -1
- package/dist/registry/embedding-manager.d.ts +9 -1
- package/dist/registry/inheritance-resolver.d.ts +8 -3
- package/dist/registry/manifest-field-merge.d.ts +2 -2
- package/dist/registry/name-resolver.d.ts +22 -2
- package/dist/registry/relationship-graph.d.ts +9 -1
- package/dist/registry/schema-builder.d.ts +8 -3
- package/dist/registry/shared-state.d.ts +12 -2
- package/dist/registry/types.d.ts +15 -7
- package/dist/registry/validator.d.ts +10 -2
- package/dist/registry.d.ts +40 -11
- package/dist/relationship-loader.d.ts +1 -1
- package/dist/run-once.d.ts +110 -1
- package/dist/runtime/client.d.ts +4 -1
- package/dist/runtime/server.d.ts +5 -2
- package/dist/scanner/import-scanner.d.ts +1 -1
- package/dist/scanner/manifest-generator.d.ts +4 -1
- package/dist/scanner/types.d.ts +4 -1
- package/dist/schema/code-generator.d.ts +6 -2
- package/dist/schema/column-data-probes.d.ts +27 -2
- package/dist/schema/ddl/base-strategy.d.ts +8 -2
- package/dist/schema/ddl/duckdb-strategy.d.ts +14 -2
- package/dist/schema/ddl/index.d.ts +2 -2
- package/dist/schema/ddl/json-duckdb-strategy.d.ts +10 -2
- package/dist/schema/ddl/materialize-manifest.d.ts +1 -1
- package/dist/schema/ddl/null-equal-index.d.ts +1 -1
- package/dist/schema/ddl/postgres-strategy.d.ts +12 -2
- package/dist/schema/ddl/sqlite-strategy.d.ts +12 -2
- package/dist/schema/ddl/types.d.ts +10 -1
- package/dist/schema/foreign-key-ddl.d.ts +2 -2
- package/dist/schema/foreign-key-orphan-report.d.ts +25 -3
- package/dist/schema/foreign-key-planner.d.ts +2 -2
- package/dist/schema/foreign-key-policy.d.ts +1 -1
- package/dist/schema/generator.d.ts +7 -3
- package/dist/schema/index-utils.d.ts +11 -2
- package/dist/schema/live-parity.d.ts +27 -3
- package/dist/schema/manifest-schema.d.ts +21 -2
- package/dist/schema/schema-aggregator.d.ts +35 -2
- package/dist/schema/schema-manager.d.ts +13 -4
- package/dist/schema/system-table-shapes.d.ts +20 -1
- package/dist/schema/table-verifier.d.ts +1 -1
- package/dist/schema/text-cast-probe.d.ts +24 -1
- package/dist/schema/utils.d.ts +13 -4
- package/dist/schema/uuid-convergence.d.ts +32 -1
- package/dist/signals/bus.d.ts +8 -2
- package/dist/signals/sanitizer.d.ts +7 -1
- package/dist/smrt-knowledge.json +8 -9
- package/dist/system/bootstrap.d.ts +2 -1
- package/dist/system/compatibility.d.ts +1 -1
- package/dist/system/diagnostics.d.ts +17 -2
- package/dist/system/retention.d.ts +46 -1
- package/dist/system/schema.d.ts +7 -1
- package/dist/system-fields.d.ts +9 -1
- package/dist/test-utils.d.ts +7 -1
- package/dist/testing/database.d.ts +18 -1
- package/dist/testing/notifications-stub.d.ts +15 -1
- package/dist/tools/tool-executor.d.ts +6 -1
- package/dist/tools/tool-generator.d.ts +8 -2
- package/dist/utils/json.d.ts +9 -1
- package/dist/utils/qualified-names.d.ts +10 -1
- package/dist/utils/scanner-module.d.ts +2 -2
- package/dist/utils.d.ts +1 -1
- package/dist/vite-plugin/api-client-entries.d.ts +9 -1
- package/dist/vite-plugin/changes-route.d.ts +33 -2
- package/dist/vite-plugin/dev-plane-route.d.ts +12 -1
- package/dist/vite-plugin/events-route.d.ts +37 -2
- package/dist/vite-plugin/generated-client.d.ts +9 -1
- package/dist/vite-plugin/index.d.ts +9 -5
- package/dist/vite-plugin/resources-route.d.ts +82 -1
- package/dist/vite-plugin/sveltekit-generator.d.ts +8 -4
- package/dist/vite-plugin/sveltekit-route-coordinator.d.ts +3 -3
- package/dist/vite-plugin/sync-apply-route.d.ts +19 -2
- package/dist/vite-plugin/web-collections.d.ts +25 -2
- package/dist/vite-plugin/worker-registration.d.ts +21 -1
- package/package.json +7 -8
- package/dist/knowledge-discovery.js.map +0 -1
- package/dist/knowledge-graph.js.map +0 -1
|
@@ -1,4 +1,47 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* SmrtPolymorphicAssociation — base class for polymorphic association rows.
|
|
3
|
+
*
|
|
4
|
+
* A polymorphic association links an owner row to an arbitrary target
|
|
5
|
+
* SmrtObject identified by a `(metaType, metaId)` pair — `metaType` being the
|
|
6
|
+
* target's qualified class name (e.g. `@happyvertical/smrt-content:Article`)
|
|
7
|
+
* and `metaId` its row id. Pair that with a `role` discriminator and a
|
|
8
|
+
* `sortOrder`, and one join table can reference many different target types
|
|
9
|
+
* without a typed foreign key per type.
|
|
10
|
+
*
|
|
11
|
+
* Subclasses add their own "owner" side and decorate with `@smrt()`:
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* @smrt({ conflictColumns: ['asset_id', 'meta_type', 'meta_id', 'role'] })
|
|
15
|
+
* export class AssetAssociation extends SmrtPolymorphicAssociation {
|
|
16
|
+
* @foreignKey('Asset', { required: true })
|
|
17
|
+
* assetId = '';
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* const target = await association.hydrate(); // resolves metaType + loads metaId
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* Convention: `metaId` is intentionally a bare string, NOT a typed
|
|
24
|
+
* `@foreignKey` / `@crossPackageRef` — it is polymorphic, so there is no
|
|
25
|
+
* single target table to point at. `metaType` carries the type information
|
|
26
|
+
* instead, resolved at runtime via `ObjectRegistry`.
|
|
27
|
+
*
|
|
28
|
+
* This is an abstract framework base in the same family as
|
|
29
|
+
* `SmrtHierarchical` and `SmrtJunction`: it has no `@smrt()` decorator and no
|
|
30
|
+
* table of its own. Its columns are merged into each concrete subclass's
|
|
31
|
+
* manifest by the scanner's `FRAMEWORK_BASE_CLASSES` /
|
|
32
|
+
* `FRAMEWORK_ABSTRACT_BASE_NAMES` wiring. Keep those two lists in sync when
|
|
33
|
+
* touching this class.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* @smrt({ conflictColumns: ['owner_id', 'meta_type', 'meta_id', 'role'] })
|
|
38
|
+
* export class CommentAssociation extends SmrtPolymorphicAssociation {
|
|
39
|
+
* @foreignKey('Comment', { required: true })
|
|
40
|
+
* ownerId = '';
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
import { SmrtObject, type SmrtObjectOptions } from './object';
|
|
2
45
|
/**
|
|
3
46
|
* Options accepted by `SmrtPolymorphicAssociation` (and its subclasses)
|
|
4
47
|
* covering the polymorphic right side of the join.
|
package/dist/prebuild/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Pre-build utilities for generating TypeScript declarations
|
|
3
|
+
* Solves virtual module resolution by creating physical .d.ts files
|
|
4
|
+
*/
|
|
5
|
+
import type { SmartObjectManifest } from '../scanner/types';
|
|
2
6
|
export interface PrebuildOptions {
|
|
3
7
|
/** Path to manifest file or manifest object */
|
|
4
8
|
manifest: string | SmartObjectManifest;
|
package/dist/query-bounds.d.ts
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query bounds for list surfaces (#2367).
|
|
3
|
+
*
|
|
4
|
+
* Every generated read surface — REST, SvelteKit routes, the MCP server and the
|
|
5
|
+
* MCP runtime bootstrap — takes `limit`/`offset` straight from untrusted input.
|
|
6
|
+
* Before this module each one parsed them by hand, and each got it wrong in a
|
|
7
|
+
* different way: `Number.parseInt('abc')` produced `LIMIT NaN` (a 500 from the
|
|
8
|
+
* driver, not a 400 from the API), `Number(x) || 50` silently turned `0` into
|
|
9
|
+
* `50`, and none of them capped the value, so `?limit=100000000` was a
|
|
10
|
+
* single-request table scan on every generated endpoint.
|
|
11
|
+
*
|
|
12
|
+
* This is the one parser they all share. It is deliberately strict on the input
|
|
13
|
+
* (a bound is a non-negative integer or it is a client error) and deliberately
|
|
14
|
+
* forgiving on magnitude (an oversized page is clamped, not rejected, so a
|
|
15
|
+
* caller paging with a too-large window still makes progress instead of
|
|
16
|
+
* receiving an error it cannot act on).
|
|
17
|
+
*
|
|
18
|
+
* The bounds themselves are also available to `SmrtCollection.list()` through
|
|
19
|
+
* the `defaultListLimit` / `maxListLimit` collection options. Those are opt-in:
|
|
20
|
+
* `list()` is the framework's own bulk-read primitive and dozens of internal
|
|
21
|
+
* callers (relationship loaders, junction hydration, `listByIds`) legitimately
|
|
22
|
+
* expect every matching row, so a framework-wide implicit default would
|
|
23
|
+
* silently truncate results rather than bound an attack surface. The bound
|
|
24
|
+
* belongs where untrusted input arrives, which is why the generated surfaces
|
|
25
|
+
* apply it unconditionally and direct programmatic callers opt in.
|
|
26
|
+
*/
|
|
1
27
|
import { ValidationError } from './errors';
|
|
2
28
|
/**
|
|
3
29
|
* Page size a generated list surface uses when the caller supplies none.
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Collection read-cache configuration resolution for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the effective `@smrt({ cache })` config for a class, walking the
|
|
5
|
+
* inheritance chain so an STI base class opt-in covers its children while a
|
|
6
|
+
* child can still opt out with `cache: false`.
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/happyvertical/smrt/issues/1498
|
|
9
|
+
*/
|
|
10
|
+
import type { CollectionCacheConfig } from '../collection-cache';
|
|
2
11
|
/**
|
|
3
12
|
* Resolve the effective collection cache config for a class.
|
|
4
13
|
*
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class registration module for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Handles registering classes, collections, and manifest entries.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from registry.ts as part of issue #1006.
|
|
7
|
+
* @see https://github.com/happyvertical/smrt/issues/1006
|
|
8
|
+
*/
|
|
1
9
|
import { SmrtObject } from '../object';
|
|
2
|
-
import { SmartObjectDefinition } from '../scanner/types.js';
|
|
3
|
-
import { RegisteredClass, RegisteredField, SmartObjectConfig } from './types.js';
|
|
10
|
+
import type { SmartObjectDefinition } from '../scanner/types.js';
|
|
11
|
+
import type { RegisteredClass, RegisteredField, SmartObjectConfig } from './types.js';
|
|
4
12
|
/**
|
|
5
13
|
* Shared bundled-context detector. Source files in these output
|
|
6
14
|
* directories come from a bundler (Vite library mode, webpack, Next.js,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RegisteredClass } from './types';
|
|
1
|
+
import type { RegisteredClass } from './types';
|
|
2
2
|
export interface CollectionRegistrationLookup {
|
|
3
3
|
findClass: (name: string) => RegisteredClass | undefined;
|
|
4
4
|
findClassInPackage?: (packageName: string, className: string) => RegisteredClass | undefined;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Embedding configuration management for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Handles class-level and project-level embedding config resolution.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from registry.ts as part of issue #1006.
|
|
7
|
+
* @see https://github.com/happyvertical/smrt/issues/1006
|
|
8
|
+
*/
|
|
9
|
+
import type { ClassEmbeddingConfig, ProjectEmbeddingConfig, ResolvedEmbeddingConfig } from '../embeddings/types';
|
|
2
10
|
/**
|
|
3
11
|
* Get embedding configuration for a class.
|
|
4
12
|
*/
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Inheritance resolution module for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from registry.ts as part of issue #1006.
|
|
5
|
+
*/
|
|
6
|
+
import type { SmrtObject } from '../object';
|
|
7
|
+
import type { MethodDefinition } from '../scanner/types.js';
|
|
8
|
+
import type { RegisteredField } from './types';
|
|
4
9
|
/**
|
|
5
10
|
* Runtime field shape merged across an inheritance chain.
|
|
6
11
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FieldDefinition } from '../scanner/types.js';
|
|
2
|
-
import { RegisteredField } from './types';
|
|
1
|
+
import type { FieldDefinition } from '../scanner/types.js';
|
|
2
|
+
import type { RegisteredField } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* Manifest-sourced field input handled by the merge helpers.
|
|
5
5
|
*
|
|
@@ -1,5 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Name resolution module for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Handles class lookup, disambiguation, and qualified name resolution.
|
|
5
|
+
* All functions operate on the shared globalThis state.
|
|
6
|
+
*
|
|
7
|
+
* Release B (#1133): classNameMap is gone — the eagerly-maintained
|
|
8
|
+
* lowercase-simple-name → qualified-key[] index was removed in favor of
|
|
9
|
+
* on-demand iteration over the `classes` Map. Production SMRT apps carry
|
|
10
|
+
* a few hundred classes at most, so the linear scan is negligible and
|
|
11
|
+
* removes an entire class of cache-sync bugs (#584, #847, #951).
|
|
12
|
+
*
|
|
13
|
+
* #3047: hydration resolves names per row, so the scan now runs once per
|
|
14
|
+
* registry generation into a derived (never hand-maintained) index; see
|
|
15
|
+
* `getSimpleNameIndex()` and `registry/generation.ts`.
|
|
16
|
+
*
|
|
17
|
+
* Extracted from registry.ts as part of issue #1006.
|
|
18
|
+
* @see https://github.com/happyvertical/smrt/issues/1006
|
|
19
|
+
* @see https://github.com/happyvertical/smrt/issues/1133
|
|
20
|
+
*/
|
|
21
|
+
import type { QualifiedClassName, SmrtVisibility } from '../scanner/types.js';
|
|
22
|
+
import type { RegisteredClass, SmrtObjectConstructor } from './types';
|
|
3
23
|
/**
|
|
4
24
|
* Check if a class is already registered (case-insensitive).
|
|
5
25
|
* Returns the canonical name if found, undefined otherwise. Returns
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Relationship graph and dependency resolution module for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Builds relationship maps and dependency graphs from registered class fields.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from registry.ts as part of issue #1006.
|
|
7
|
+
* @see https://github.com/happyvertical/smrt/issues/1006
|
|
8
|
+
*/
|
|
9
|
+
import type { RelationshipMetadata } from './types';
|
|
2
10
|
/** Canonical target of the field's declaring class, including inherited fields. */
|
|
3
11
|
export declare function resolveRelationshipTarget(className: string, fieldName: string): string | null | undefined;
|
|
4
12
|
/**
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Schema building logic for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from registry.ts as part of issue #1006.
|
|
5
|
+
*/
|
|
6
|
+
import type { FieldDefinition } from '../scanner/types.js';
|
|
7
|
+
import type { DatabaseEngine } from '../schema/ddl/types.js';
|
|
8
|
+
import type { ColumnDefinition, SchemaDefinition, SQLDataType } from '../schema/types.js';
|
|
4
9
|
/**
|
|
5
10
|
* Get cached schema definition for a registered class
|
|
6
11
|
*
|
|
@@ -1,6 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Shared state accessors for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* All registry sub-modules share state via globalThis to ensure
|
|
5
|
+
* cross-module consistency in monorepo environments.
|
|
6
|
+
*
|
|
7
|
+
* Extracted from registry.ts as part of issue #1006.
|
|
8
|
+
* @see https://github.com/happyvertical/smrt/issues/1006
|
|
9
|
+
* @see https://github.com/happyvertical/smrt/issues/543
|
|
10
|
+
*/
|
|
11
|
+
import type { SmrtCollection } from '../collection';
|
|
2
12
|
import { LRUCache } from '../utils/lru-cache';
|
|
3
|
-
import { RegisteredClass, SmrtObjectConstructor } from './types';
|
|
13
|
+
import type { RegisteredClass, SmrtObjectConstructor } from './types';
|
|
4
14
|
declare global {
|
|
5
15
|
var __smrtRegistryClasses: Map<string, RegisteredClass> | undefined;
|
|
6
16
|
var __smrtRegistryCollections: Map<string, typeof SmrtCollection> | undefined;
|
package/dist/registry/types.d.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from registry.ts as part of issue #1006
|
|
5
|
+
* (Split ObjectRegistry into focused modules).
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/happyvertical/smrt/issues/1006
|
|
8
|
+
*/
|
|
9
|
+
import type { CapabilityEffect, DomainKnowledgeConfig } from '@happyvertical/smrt-types';
|
|
10
|
+
import type { SmrtCollection } from '../collection';
|
|
11
|
+
import type { CollectionCacheConfig } from '../collection-cache';
|
|
12
|
+
import type { FieldOptions } from '../decorators/index.js';
|
|
13
|
+
import type { SmrtObject } from '../object';
|
|
14
|
+
import type { FieldDefinition, FieldMeta, MethodDefinition, QualifiedClassName, SmartObjectManifest, SmrtVisibility, ValidationRule } from '../scanner/types.js';
|
|
15
|
+
import type { DeclaredIndexDefinition, SchemaDefinition } from '../schema/types.js';
|
|
8
16
|
/**
|
|
9
17
|
* Type for any constructor function that extends SmrtObject.
|
|
10
18
|
* Used for WeakMap keys where we need to accept any subclass constructor.
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Validator module for the SMRT ObjectRegistry.
|
|
3
|
+
*
|
|
4
|
+
* Compiles validation functions from field definitions for runtime use.
|
|
5
|
+
*
|
|
6
|
+
* Extracted from registry.ts as part of issue #1006.
|
|
7
|
+
* @see https://github.com/happyvertical/smrt/issues/1006
|
|
8
|
+
*/
|
|
9
|
+
import type { FieldDefinition } from '../scanner/types.js';
|
|
10
|
+
import type { ValidatorFunction } from './types';
|
|
3
11
|
export declare function isBatchSafeValidator(validator: ValidatorFunction): boolean;
|
|
4
12
|
/**
|
|
5
13
|
* Compile validation functions from field definitions.
|
package/dist/registry.d.ts
CHANGED
|
@@ -1,14 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import {
|
|
1
|
+
/**
|
|
2
|
+
* Global object registry for SMRT classes
|
|
3
|
+
*
|
|
4
|
+
* Maintains a central registry of all @smrt decorated classes, enabling
|
|
5
|
+
* module awareness, automatic API generation, and runtime introspection.
|
|
6
|
+
* The registry tracks class definitions, field metadata, and configuration
|
|
7
|
+
* options for code generation and runtime operations.
|
|
8
|
+
*
|
|
9
|
+
* @example Registering a class manually
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { ObjectRegistry } from '@happyvertical/smrt-core';
|
|
12
|
+
*
|
|
13
|
+
* ObjectRegistry.register(MyClass, {
|
|
14
|
+
* api: { exclude: ['delete'] },
|
|
15
|
+
* cli: true
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @example Using the decorator (recommended)
|
|
20
|
+
* ```typescript
|
|
21
|
+
* import { smrt, field } from '@happyvertical/smrt-core';
|
|
22
|
+
*
|
|
23
|
+
* @smrt({ api: { exclude: ['delete'] } })
|
|
24
|
+
* class Product extends SmrtObject {
|
|
25
|
+
* @field({ required: true })
|
|
26
|
+
* name: string = '';
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
import { SmrtCollection, type SmrtCollectionOptions } from './collection';
|
|
31
|
+
import type { CollectionCacheConfig } from './collection-cache';
|
|
32
|
+
import type { FieldOptions, MethodOptions } from './decorators/index.js';
|
|
33
|
+
import type { ClassEmbeddingConfig, ProjectEmbeddingConfig, ResolvedEmbeddingConfig } from './embeddings/types';
|
|
34
|
+
import type { ValidationError } from './errors';
|
|
35
|
+
import type { SmrtObject } from './object';
|
|
36
|
+
import { type RegistryDiagnostic } from './registry/diagnostics';
|
|
37
|
+
import type { RegisteredClass, RegisteredField, RelationshipMetadata, SmartObjectConfig, SmrtObjectConstructor, ValidatorFunction } from './registry/types';
|
|
38
|
+
import type { MethodDefinition, QualifiedClassName, SmartObjectDefinition, SmartObjectManifest, SmrtVisibility, ValidationRule } from './scanner/types.js';
|
|
39
|
+
import type { DatabaseEngine } from './schema/ddl/types.js';
|
|
40
|
+
import type { SchemaDefinition } from './schema/types.js';
|
|
12
41
|
export { isSmrtCollectionExtendsName, SMRT_COLLECTION_BASE_NAMES, } from './registry/collection-resolution';
|
|
13
42
|
export { isFrameworkBaseClass } from './registry/framework-base-classes';
|
|
14
43
|
export type { RelationshipMetadata, RelationshipType, SmartObjectConfig, } from './registry/types';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RelationshipMetadata } from './registry';
|
|
1
|
+
import { type RelationshipMetadata } from './registry';
|
|
2
2
|
/** Resolve the identity used for I/O, never the public display-name alias. */
|
|
3
3
|
export declare function resolveRelationshipTargetName(relationship: RelationshipMetadata): Promise<string>;
|
|
4
4
|
/** One inverse selection contract for lazy, eager and joined readers. */
|
package/dist/run-once.d.ts
CHANGED
|
@@ -1,4 +1,113 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Idempotency seam: run an action exactly once per submission (#3080).
|
|
3
|
+
*
|
|
4
|
+
* Every consumer with a form, a retried request, or a double-tapped button
|
|
5
|
+
* needs the same guard: a claim row, insert-only against a UNIQUE column
|
|
6
|
+
* (`claim_key`) in the SAME transaction as the work it guards, so a retry
|
|
7
|
+
* either runs the work once or replays the first attempt's stored result.
|
|
8
|
+
* This module is that primitive. It is DB/transaction-level — it takes a
|
|
9
|
+
* `DatabaseInterface`, not a `SmrtObject`/`SmrtCollection` — so it works
|
|
10
|
+
* outside SvelteKit and outside the ORM: any caller with a database handle
|
|
11
|
+
* and a JSON-serializable work result can use it. The claim insert itself
|
|
12
|
+
* is raw SQL (`## Concurrent submissions` below explains why), not the
|
|
13
|
+
* ORM's `SmrtObject`-level `_insertOnly` option.
|
|
14
|
+
*
|
|
15
|
+
* ## Key derivation (not the token alone)
|
|
16
|
+
*
|
|
17
|
+
* The claim key is the sha256 hex digest of the sorted-key-JSON encoding of
|
|
18
|
+
* `[tenantId, actor, token, contentDigest]`, where `contentDigest` is itself
|
|
19
|
+
* the sha256 hex digest of the sorted-key-JSON encoding of `content`
|
|
20
|
+
* ({@link digestRunOnceContent}). Sorted-key JSON ({@link stableStringify},
|
|
21
|
+
* `./knowledge-graph.ts`) makes the digest stable regardless of property
|
|
22
|
+
* insertion order.
|
|
23
|
+
*
|
|
24
|
+
* The token alone is NOT the key. A first attempt at this exact problem
|
|
25
|
+
* (reported against #3080) keyed on the token alone and silently collapsed
|
|
26
|
+
* two genuinely different submissions that happened to reuse one form's
|
|
27
|
+
* token. Folding in the content digest means a retry of the SAME submission
|
|
28
|
+
* (same token, same content) replays; a DIFFERENT submission through the
|
|
29
|
+
* same token (edited content before a resubmit) runs as its own claim.
|
|
30
|
+
* Folding in `tenantId` and `actor` means two tenants or two actors can never
|
|
31
|
+
* collide on the same claim even if a token were somehow shared between them.
|
|
32
|
+
*
|
|
33
|
+
* Neither the raw token nor the raw content is ever persisted — only their
|
|
34
|
+
* digests — so the claims table (`_smrt_run_once_claims`,
|
|
35
|
+
* `./system/schema.ts`) cannot leak submitted business data.
|
|
36
|
+
*
|
|
37
|
+
* ## Atomicity
|
|
38
|
+
*
|
|
39
|
+
* `runOnce()` opens its own `db.transaction()` (or nests under the caller's,
|
|
40
|
+
* per `@happyvertical/sql`'s own SAVEPOINT/`NestedTransactionError` rules —
|
|
41
|
+
* see that package's `DatabaseInterface.transaction` doc) and, inside it:
|
|
42
|
+
*
|
|
43
|
+
* 1. Inserts the claim row (`status: 'in_progress'`).
|
|
44
|
+
* 2. Runs `work(tx)`, passing the SAME transaction-bound handle, so the
|
|
45
|
+
* caller's writes and the claim insert commit or roll back together.
|
|
46
|
+
* 3. Updates the claim row to `status: 'completed'` with the JSON-serialized
|
|
47
|
+
* result, still inside the same transaction.
|
|
48
|
+
*
|
|
49
|
+
* If `work()` throws, the callback throws, and `db.transaction()`'s own
|
|
50
|
+
* "commits on success, rolls back on error" contract undoes the claim insert
|
|
51
|
+
* along with whatever `work()` partially wrote — a claim is never stranded
|
|
52
|
+
* `'in_progress'` by a failed attempt, and a retry with the same key can
|
|
53
|
+
* always run again.
|
|
54
|
+
*
|
|
55
|
+
* ## Concurrent submissions
|
|
56
|
+
*
|
|
57
|
+
* The claim insert uses `INSERT ... ON CONFLICT (claim_key) DO NOTHING
|
|
58
|
+
* RETURNING claim_key` (the same portable idiom `_smrt_migrations` already
|
|
59
|
+
* uses in `system/bootstrap.ts`), not a plain `INSERT` caught for a
|
|
60
|
+
* classified `unique_violation`. This matters on PostgreSQL specifically: a
|
|
61
|
+
* statement that raises an error aborts the WHOLE transaction ("current
|
|
62
|
+
* transaction is aborted, commands ignored until end of transaction block"),
|
|
63
|
+
* so a plain `INSERT` failing on the claim key would make every subsequent
|
|
64
|
+
* statement in the same transaction — including the very `SELECT` this
|
|
65
|
+
* function needs to read the winner's stored result back — fail too.
|
|
66
|
+
* `DO NOTHING` never raises: it returns zero rows instead, which this
|
|
67
|
+
* function reads as "lost the race" without ever touching the transaction's
|
|
68
|
+
* error state. SQLite and DuckDB both support the same `ON CONFLICT ... DO
|
|
69
|
+
* NOTHING` / `RETURNING` syntax, so one query works on every adapter.
|
|
70
|
+
*
|
|
71
|
+
* `@happyvertical/sql`'s single-connection adapters (SQLite, DuckDB, JSON)
|
|
72
|
+
* serialize `transaction()` calls on one connection: a second, concurrent
|
|
73
|
+
* `runOnce()` call does not begin its own transaction until the first one
|
|
74
|
+
* ends. PostgreSQL pools, but this `INSERT`'s arbiter still has to check the
|
|
75
|
+
* unique index against another transaction's uncommitted row of the same
|
|
76
|
+
* PRIMARY KEY, and blocks until that transaction resolves, then either
|
|
77
|
+
* no-ops (committed — the row exists) or inserts (rolled back — no row).
|
|
78
|
+
* Either way, two concurrent callers with the same key never both run
|
|
79
|
+
* `work()`: exactly one does, and the loser's `INSERT` returns zero rows —
|
|
80
|
+
* never an error — at which point it reads the now-committed claim row back
|
|
81
|
+
* and replays its stored result.
|
|
82
|
+
*
|
|
83
|
+
* ## Typed answers for a claim that is not (yet) a definite result
|
|
84
|
+
*
|
|
85
|
+
* A `runOnce()` conflict is a *definite* decision — the row exists — but
|
|
86
|
+
* whether it is safe to hand back a result depends on `status`. This mirrors
|
|
87
|
+
* the "refused vs unknown outcome" distinction #2990 drew for AssistantDock
|
|
88
|
+
* actions (`./errors.ts#RunOnceClaimError` carries the two codes):
|
|
89
|
+
*
|
|
90
|
+
* - `status: 'completed'` — replay the stored `result`. No error.
|
|
91
|
+
* - `status` anything else (still `'in_progress'`) — some execution holds
|
|
92
|
+
* this key right now. `RunOnceClaimError.inFlight()`. Under this module's
|
|
93
|
+
* own transaction semantics this is normally unreachable through
|
|
94
|
+
* `runOnce()`-to-`runOnce()` races alone (the losing transaction can only
|
|
95
|
+
* ever observe a COMMITTED row, and this module only ever commits a row
|
|
96
|
+
* once it is `'completed'`) — it is reachable if a claim row was inserted
|
|
97
|
+
* outside this module's own completion discipline, and is kept as a
|
|
98
|
+
* defined answer rather than an assumption.
|
|
99
|
+
* - the row cannot be read back at all after `DO NOTHING` reported zero
|
|
100
|
+
* rows inserted — `RunOnceClaimError.outcomeUnknown()`. Also normally
|
|
101
|
+
* unreachable (the zero-rows case only happens when a committed row
|
|
102
|
+
* already exists); kept for adapters/drivers where that and a subsequent
|
|
103
|
+
* read are not guaranteed to observe the same committed state.
|
|
104
|
+
*
|
|
105
|
+
* Both errors carry `claimKey` and are safe to retry with the SAME token and
|
|
106
|
+
* content; `runOnce()` never retries them itself.
|
|
107
|
+
*
|
|
108
|
+
* @module
|
|
109
|
+
*/
|
|
110
|
+
import type { DatabaseInterface } from '@happyvertical/sql';
|
|
2
111
|
import { RUN_ONCE_CLAIMS_TABLE } from './system/schema.js';
|
|
3
112
|
export { RUN_ONCE_CLAIMS_TABLE };
|
|
4
113
|
/** Input identifying one submission for {@link runOnce}. */
|
package/dist/runtime/client.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Runtime client implementation for SMRT auto-generated services
|
|
3
|
+
*/
|
|
4
|
+
import type { SmrtClientOptions } from './types';
|
|
2
5
|
export declare class SmrtClient {
|
|
3
6
|
private options;
|
|
4
7
|
constructor(options?: SmrtClientOptions);
|
package/dist/runtime/server.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Runtime server implementation for SMRT auto-generated services
|
|
3
|
+
*/
|
|
4
|
+
import http from 'node:http';
|
|
5
|
+
import type { SmrtRequest, SmrtServerOptions } from './types';
|
|
3
6
|
/**
|
|
4
7
|
* Express-style response object handed to RouteApp-compatibility handlers
|
|
5
8
|
* (registered via {@link SmrtServer.get}/`post`/`put`/`delete`). It mirrors the
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Manifest generator for creating service manifests from AST scan results
|
|
3
|
+
*/
|
|
4
|
+
import type { ScanResult, SmartObjectManifest, SmrtVisibility } from './types.js';
|
|
2
5
|
/** Package.json shape consumed for import-path and component discovery. */
|
|
3
6
|
interface PackageJsonLike {
|
|
4
7
|
name?: string;
|
package/dist/scanner/types.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for AST scanning and manifest generation
|
|
3
|
+
*/
|
|
4
|
+
import type { SmartObjectConfig } from '../registry.js';
|
|
2
5
|
/**
|
|
3
6
|
* Qualified class name in format "@package/name:ClassName"
|
|
4
7
|
* Example: "@happyvertical/smrt-core:Product"
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Code generator for SMRT schema methods
|
|
3
|
+
* Generates getSchema() static methods for SMRT objects
|
|
4
|
+
*/
|
|
5
|
+
import type { SmartObjectDefinition } from '../scanner/types.js';
|
|
6
|
+
import type { SchemaDefinition } from './types.js';
|
|
3
7
|
export declare class SchemaCodeGenerator {
|
|
4
8
|
/**
|
|
5
9
|
* Generate getSchema() method source code
|
|
@@ -1,5 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Shared live-data column probes (#2874, consolidated for #2878).
|
|
3
|
+
*
|
|
4
|
+
* `detectRenameDataPending()` exists in both `migrations/differ.ts` and
|
|
5
|
+
* `schema/live-parity.ts` — tracked as its own maintenance hazard by #2878,
|
|
6
|
+
* since the #2874 regression had to be fixed twice, in lockstep, in #2876
|
|
7
|
+
* (once per copy). Until now the two batched live-data probes that function
|
|
8
|
+
* depends on were duplicated right along with it: does a named column hold
|
|
9
|
+
* any non-empty value, and does every non-empty value in a named column
|
|
10
|
+
* look UUID-shaped? Both copies used the exact same shape —
|
|
11
|
+
* uncorrelated scalar subqueries, one per column, each with its own
|
|
12
|
+
* `LIMIT 1` early exit (#2874 review finding F1: never an aggregate over
|
|
13
|
+
* the whole table, which would force a full scan per probed column even
|
|
14
|
+
* when the very first row already answers it), and the same positional
|
|
15
|
+
* `c<index>` aliasing to sidestep PostgreSQL's 63-byte identifier
|
|
16
|
+
* truncation (#2874 review finding F2'). Extracted here so the two call
|
|
17
|
+
* sites can never drift out of lockstep again.
|
|
18
|
+
*
|
|
19
|
+
* Both functions fall back to isolated per-column probing when the batched
|
|
20
|
+
* statement itself fails, so one bad column (dropped concurrently, a `CAST`
|
|
21
|
+
* the engine rejects) withholds only that column's result rather than the
|
|
22
|
+
* whole table's (#2874 review finding F2). A column absent from the
|
|
23
|
+
* returned map means "could not be probed" — callers apply their own
|
|
24
|
+
* fail-closed default, not this module.
|
|
25
|
+
*/
|
|
26
|
+
import type { DatabaseInterface } from '@happyvertical/sql';
|
|
27
|
+
import type { DatabaseEngine } from './ddl/types.js';
|
|
3
28
|
/**
|
|
4
29
|
* SQL predicate: a quoted column holds a non-null, non-empty value. Shared
|
|
5
30
|
* by every probe below (single-table batch, single-column fallback, and
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Base DDL Strategy - Shared logic for all database engines
|
|
3
|
+
*
|
|
4
|
+
* Provides common DDL generation logic that engine-specific strategies
|
|
5
|
+
* can override for their particular requirements.
|
|
6
|
+
*/
|
|
7
|
+
import type { ColumnDefinition, IndexDefinition, SchemaDefinition, SQLDataType, TriggerDefinition } from '../types.js';
|
|
8
|
+
import type { DatabaseEngine, DDLStrategy } from './types.js';
|
|
3
9
|
/**
|
|
4
10
|
* Abstract base class for DDL strategies
|
|
5
11
|
*
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* DuckDB DDL Strategy
|
|
3
|
+
*
|
|
4
|
+
* DuckDB-specific DDL generation with the following characteristics:
|
|
5
|
+
* - UNIQUE constraints MUST be inline for UPSERT to work (DuckDB issue #12684)
|
|
6
|
+
* - Supports CAST in DEFAULT values
|
|
7
|
+
* - Native BOOLEAN, JSON types
|
|
8
|
+
* - Does NOT support triggers
|
|
9
|
+
*
|
|
10
|
+
* CRITICAL: DuckDB's ON CONFLICT clause only works with inline UNIQUE constraints,
|
|
11
|
+
* not with separate UNIQUE indexes. This is a known DuckDB limitation.
|
|
12
|
+
*/
|
|
13
|
+
import type { SchemaDefinition, SQLDataType } from '../types.js';
|
|
2
14
|
import { BaseDDLStrategy } from './base-strategy.js';
|
|
3
|
-
import { DatabaseEngine } from './types.js';
|
|
15
|
+
import type { DatabaseEngine } from './types.js';
|
|
4
16
|
export declare class DuckDBStrategy extends BaseDDLStrategy {
|
|
5
17
|
readonly engine: DatabaseEngine;
|
|
6
18
|
generateCreateTable(schema: SchemaDefinition): string;
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { SchemaDefinition } from '../types.js';
|
|
2
|
-
import { DatabaseEngine, DDLStrategy, EngineSpecificDDL, MultiEngineDDL } from './types.js';
|
|
3
1
|
/**
|
|
4
2
|
* DDL Generator Module
|
|
5
3
|
*
|
|
@@ -12,6 +10,8 @@ export { JsonDuckDBStrategy } from './json-duckdb-strategy.js';
|
|
|
12
10
|
export { PostgresStrategy } from './postgres-strategy.js';
|
|
13
11
|
export { SQLiteStrategy } from './sqlite-strategy.js';
|
|
14
12
|
export * from './types.js';
|
|
13
|
+
import type { SchemaDefinition } from '../types.js';
|
|
14
|
+
import type { DatabaseEngine, DDLStrategy, EngineSpecificDDL, MultiEngineDDL } from './types.js';
|
|
15
15
|
/**
|
|
16
16
|
* Get the DDL strategy for a specific database engine
|
|
17
17
|
*
|