graphddb 0.3.0 → 0.4.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/README.md +1 -0
- package/dist/{chunk-6AIAHP3A.js → chunk-72VZYOSG.js} +850 -1
- package/dist/{chunk-QQNP43JL.js → chunk-GWFZVNAV.js} +347 -2
- package/dist/{chunk-QEOFIXTN.js → chunk-PC54CW5P.js} +231 -554
- package/dist/cli.js +2 -2
- package/dist/index.d.ts +673 -5
- package/dist/index.js +658 -21
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +2 -2
- package/dist/{types-xJRn5qkv.d.ts → types-CpCo8yHP.d.ts} +398 -66
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SelectableOf, g as PrimaryKeyOf, h as RequestContext, i as Middleware, j as ReadRequestKind, k as CtxModel, l as ReadParams, m as ReadRequestCtx, D as DynamoDBOperation, I as Item, E as Executor, n as RetryPolicy, o as ExecutionPlanSpec, p as EntityMetadata, K as KeyDefinition, G as GsiDefinition, F as FieldOptions,
|
|
2
|
-
export {
|
|
1
|
+
import { S as SelectableOf, g as PrimaryKeyOf, h as RequestContext, i as Middleware, j as ReadRequestKind, k as CtxModel, l as ReadParams, m as ReadRequestCtx, D as DynamoDBOperation, I as Item, E as Executor, n as RetryPolicy, o as ExecutionPlanSpec, p as EntityMetadata, K as KeyDefinition, G as GsiDefinition, q as ModelKind, F as FieldOptions, r as DynamoType, s as ProjectionTransform, t as MaintainEvent, u as MembershipPredicate, v as MaintainConsistency, w as MaintainUpdateMode, x as MembershipPredicateOp, y as RelationOptions, A as AggregateOptions, z as AggregateValue, H as SelectBuilderSpec, J as RawCondition, L as TransactionSpec, N as Manifest, O as RetryOverride, Q as ExecutionPlan, V as FieldMetadata, X as ResolvedKey, R as ReadExecOptions, a as ExecutorResult, B as BatchGetExecInput, P as PutInput, W as WriteExecOptions, b as WriteResult, U as UpdateInput, c as DeleteInput, d as BatchWriteExecItem, e as BatchExecOptions, T as TransactWriteExecItem, Y as CdcEmulatorOptions, Z as ChangeHandler, _ as Unsubscribe, $ as FaultSpec, a0 as ConcurrentRecomputeRef, C as ChangeEvent, a1 as EventLog, a2 as ReplayOptions, a3 as ShardId, a4 as ViewDefinition, a5 as RelationMetadata, a6 as TransactionItemSpec, a7 as MaintainEffect, M as ModelStatic, f as DDBModel, a8 as Param, a9 as ParamDescriptor, aa as DefinitionMap, ab as OperationDefinition, ac as WriteDefinitionOptions, ad as PartialQueryKeyOf, ae as StrictSelectSpec, af as EntityInput, ag as UniqueQueryKeyOf, ah as EntityRef, ai as ConditionInput, aj as QueryModelContract, ak as QueryMethodSpec, al as CommandModelContract, am as CommandMethodSpec, an as ContractSpec, ao as QuerySpec, ap as CommandSpec, aq as ContextSpec, ar as OperationsDocument, as as AnyOperationDefinition, at as BridgeBundle, au as ConditionSpec } from './types-CpCo8yHP.js';
|
|
2
|
+
export { av as AggregateMetadata, aw as BatchDeleteRequest, ax as BatchGetOptions, ay as BatchGetRequest, az as BatchGetResult, aA as BatchPutRequest, aB as BatchResult, aC as BatchWriteRequest, aD as CONTRACT_RANGE_FANOUT_CONCURRENCY, aE as CdcMode, aF as Change, aG as ChangeBatch, aH as ChangeEventName, aI as ClockMode, aJ as CollectionEffect, aK as CollectionOptions, aL as Column, aM as ColumnMap, aN as CommandContractMethodSpec, aO as CommandInputShape, aP as CommandMethod, aQ as CommandPlan, aR as CommandResolutionTarget, aS as CommandResultKind, aT as CommandSelectShape, aU as CompiledFragment, aV as ComposeSpec, aW as CondSlot, aX as ConditionCheckInput, aY as Connection, aZ as ContractCallSignature, a_ as ContractCardinality, a$ as ContractCommandParams, b0 as ContractCommandResult, b1 as ContractComposeNode, b2 as ContractFromRef, b3 as ContractInputArity, b4 as ContractItem, b5 as ContractKeyFieldRef, b6 as ContractKeyInput, b7 as ContractKeyRef, b8 as ContractKeySpec, b9 as ContractKind, ba as ContractMethodOp, bb as ContractParamRef, bc as ContractQueryParams, bd as ContractResolution, be as CounterAggregate, bf as CounterEffect, bg as CtxBase, bh as DEFAULT_MAX_ATTEMPTS, bi as DEFAULT_RETRY_POLICY, bj as DeleteOptions, bk as DeriveEffect, bl as DerivedEdgeWrite, bm as DerivedUpdate, bn as DescriptorBinding, bo as ENTITY_WRITES_MARKER, bp as EdgeEffect, bq as EffectPath, br as EmbeddedMetadata, bs as EmitEffect, bt as EntityWritesDefinition, bu as EntityWritesShape, bv as ExecutableCommandContract, bw as ExecutableQueryContract, bx as FilterInput, by as FilterSpec, bz as FragmentInput, bA as GsiDefinitionMarker, bB as GsiOptions, bC as IdempotencyEffect, bD as InProcessWriteDescriptor, bE as InputArity, bF as KeyDefinitionMarker, bG as KeySegment, bH as KeySlot, bI as KeyStructure, bJ as KeyedResult, bK as LIFECYCLE_CONTRACT_MARKER, bL as LifecycleContract, bM as LifecycleEffects, bN as LiteralParam, bO as MaintainItem, bP as MaintainTrigger, bQ as MaintenanceGraph, bR as ManifestEntity, bS as ManifestField, bT as ManifestFieldType, bU as ManifestGsi, bV as ManifestKey, bW as ManifestRelation, bX as ManifestTable, bY as MembershipEffect, bZ as ModelRef, b_ as MutateMode, b$ as MutateOptions, c0 as MutateParallelResult, c1 as MutateTransactionResult, c2 as MutationBody, c3 as MutationDescriptorMap, c4 as MutationFragment, c5 as MutationInputProxy, c6 as MutationInputRef, c7 as MutationIntent, c8 as NumberParam, c9 as OperationKind, ca as OperationSpec, cb as ParallelOpResult, cc as ParamKind, cd as ParamSpec, ce as ParamStructure, cf as PersistCtx, cg as PersistOrigin, ch as PlannedCommandMethod, ci as ProjectionMap, cj as ProjectionTransformOp, ck as PutOptions, cl as QueryContractMethodSpec, cm as QueryEnvelopeResult, cn as QueryKeyOf, co as QueryMethod, cp as QueryResult, cq as RangeConditionSpec, cr as ReadEnvelope, cs as ReadOpCtx, ct as ReadOpKind, cu as ReadOperationType, cv as ReadRouteDescriptor, cw as ReadRouteOptions, cx as ReadRouteResult, cy as RecordedCompose, cz as RelationBuilder, cA as RelationConsistency, cB as RelationLimitOptions, cC as RelationPattern, cD as RelationProjection, cE as RelationReadOptions, cF as RelationSelect, cG as RelationSpec, cH as RelationUpdateMode, cI as RelationWriteOptions, cJ as RequiresEffect, cK as Resolution, cL as RetryInfo, cM as RetryOperationKind, cN as SPEC_VERSION, cO as SegmentSpec, cP as SegmentedKey, cQ as SelectBuilder, cR as SelectOf, cS as SnapshotEffect, cT as StartingPosition, cU as StreamViewType, cV as StringParam, cW as TransactionContext, cX as TransactionItemType, cY as UniqueEffect, cZ as Updatable, c_ as UpdateOptions, c$ as ViewSourceSlice, d0 as WhenSpec, d1 as WriteCtx, d2 as WriteDescriptor, d3 as WriteEnvelope, d4 as WriteInput, d5 as WriteKind, d6 as WriteLifecyclePhase, d7 as WriteMiddleware, d8 as WriteOperationType, d9 as WriteRecorder, da as WriteResultProjection, db as attachModelClass, dc as buildDeleteInput, dd as buildMaintenanceGraph, de as buildPutInput, df as buildUpdateInput, dg as collectViewDefinitions, dh as compileFragment, di as compileMutationPlan, dj as compileSingleFragmentPlan, dk as cond, dl as contractOfMethodSpec, dm as definePlan, dn as entityWrites, dp as executeBatchGet, dq as executeBatchWrite, dr as executeCommandMethod, ds as executeDelete, dt as executeKeyedBatchGet, du as executePut, dv as executeQueryMethod, dw as executeRangeFanout, dx as executeTransaction, dy as executeUpdate, dz as from, dA as getEntityWrites, dB as gsi, dC as identity, dD as isColumn, dE as isCommandModelContract, dF as isCommandPlan, dG as isContractComposeNode, dH as isContractFromRef, dI as isContractKeyFieldRef, dJ as isContractKeyRef, dK as isContractParamRef, dL as isEntityWritesDefinition, dM as isKeySegment, dN as isLifecycleContract, dO as isMaintainTrigger, dP as isMutationFragment, dQ as isMutationInputRef, dR as isParam, dS as isPlannedCommandMethod, dT as isQueryModelContract, dU as isRetryableError, dV as isRetryableTransactionCancellation, dW as k, dX as key, dY as lifecyclePhaseForIntent, dZ as maintainTrigger, d_ as mintContractKeyFieldRef, d$ as mintContractParamRef, e0 as mutation, e1 as param, e2 as preview, e3 as publicCommandModel, e4 as publicQueryModel, e5 as query, e6 as resolveLifecycle, e7 as wholeKeysSentinel } from './types-CpCo8yHP.js';
|
|
3
3
|
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
|
|
4
4
|
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
|
|
5
5
|
|
|
@@ -378,6 +378,14 @@ declare function validateGsiAmbiguity(primaryKey: KeyDefinition | null, gsiDefin
|
|
|
378
378
|
interface ModelOptions {
|
|
379
379
|
table: string;
|
|
380
380
|
prefix?: string;
|
|
381
|
+
/**
|
|
382
|
+
* The model's maintenance kind (issue #152). Defaults to `'entity'` (a plain
|
|
383
|
+
* stored entity). `'materializedView'` / `'sparseView'` mark it a maintained view
|
|
384
|
+
* row whose `@maintainedFrom` declarations feed the maintenance graph. A
|
|
385
|
+
* `sparseView` requires every `@maintainedFrom` to carry a `when` predicate (the
|
|
386
|
+
* adapter validates this).
|
|
387
|
+
*/
|
|
388
|
+
kind?: ModelKind;
|
|
381
389
|
}
|
|
382
390
|
declare function model(options: ModelOptions): (target: Function, context: ClassDecoratorContext) => void;
|
|
383
391
|
|
|
@@ -481,9 +489,294 @@ declare const map: FieldDecorator<Record<string, unknown>>;
|
|
|
481
489
|
|
|
482
490
|
declare function embedded(modelFactory: () => new (...args: unknown[]) => unknown): (_value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
483
491
|
|
|
484
|
-
|
|
492
|
+
/**
|
|
493
|
+
* Symbolic `(self, source) =>` evaluation for the `@maintainedFrom` view authoring
|
|
494
|
+
* and the versioned relation `pattern` union (issue #152).
|
|
495
|
+
*
|
|
496
|
+
* ## Why this module exists (existing-mechanism reuse, not a new invention)
|
|
497
|
+
*
|
|
498
|
+
* `key()` / `gsi()` already evaluate an author callback by handing it a **Proxy
|
|
499
|
+
* accessor** (`createColumnMap`, `src/select/column.ts`): any `c.<field>` access
|
|
500
|
+
* returns a branded {@link import('../select/column.js').Column} sentinel carrying
|
|
501
|
+
* the field NAME, never a real value — so the structure (which field is
|
|
502
|
+
* referenced, where) is captured verbatim and a value transform is structurally
|
|
503
|
+
* impossible. The maintained-authoring `(self, source) =>` callback is the SAME
|
|
504
|
+
* shape of problem (capture *which* source/self field fills *which* output slot,
|
|
505
|
+
* declaratively), so it reuses the SAME Proxy-sentinel mechanism, specialized to
|
|
506
|
+
* the two roots the maintained vocabulary needs:
|
|
507
|
+
*
|
|
508
|
+
* - **`source.<field>`** → a {@link SourceRef} sentinel whose `path` is the
|
|
509
|
+
* payload-rooted `$.entity.<field>` the existing maintenance IR
|
|
510
|
+
* ({@link import('../define/entity-writes.js').ProjectionTransform}) reads. This
|
|
511
|
+
* is the value position (a projected value / key value / order-by / predicate
|
|
512
|
+
* operand). Typed `keyof Source`.
|
|
513
|
+
* - **`self.<field>`** → a {@link SelfRef} sentinel naming a field of the view /
|
|
514
|
+
* relation-target model (the `collection.field` position — which view attribute
|
|
515
|
+
* holds the maintained list). Typed `keyof Self`.
|
|
516
|
+
*
|
|
517
|
+
* The output-attribute *names* (the keys of `keyBind` / `project`) are plain
|
|
518
|
+
* `keyof Self` string literals — NOT computed keys — exactly the "key = name
|
|
519
|
+
* (typed string), value = reference (proxy)" rule the issue fixes.
|
|
520
|
+
*
|
|
521
|
+
* The lowering target is UNCHANGED: a {@link SourceRef} lowers to the same
|
|
522
|
+
* `$.entity.<field>` path the old string-based builder produced, so the maintenance
|
|
523
|
+
* IR (`ViewSourceSlice` / `MaintainEffect`) is byte-identical — only the authoring
|
|
524
|
+
* surface (this symbolic capture) is new.
|
|
525
|
+
*/
|
|
526
|
+
|
|
527
|
+
/** Brand identifying a {@link SourceRef} (`source.<field>`) at runtime. */
|
|
528
|
+
declare const SOURCE_REF: unique symbol;
|
|
529
|
+
/** Brand identifying a {@link SelfRef} (`self.<field>`) at runtime. */
|
|
530
|
+
declare const SELF_REF: unique symbol;
|
|
531
|
+
/**
|
|
532
|
+
* A captured reference to a **source** field (`source.<field>`), the value
|
|
533
|
+
* position of the maintained vocabulary. Carries the field name and the
|
|
534
|
+
* payload-rooted `$.entity.<field>` {@link path} the maintenance IR reads. Branded
|
|
535
|
+
* so the adapter can distinguish a faithful reference from a literal and reject a
|
|
536
|
+
* coerced / mis-used reference loudly.
|
|
537
|
+
*/
|
|
538
|
+
interface SourceRef {
|
|
539
|
+
readonly [SOURCE_REF]: true;
|
|
540
|
+
/** The source field name (e.g. `authorId`). */
|
|
541
|
+
readonly field: string;
|
|
542
|
+
/** The payload-rooted source value path (`$.entity.<field>`). */
|
|
543
|
+
readonly path: string;
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* A captured reference to a **self** field (`self.<field>`), naming a field of the
|
|
547
|
+
* model being defined (the view / relation-target). Used in the `collection.field`
|
|
548
|
+
* position (which attribute holds the maintained list). Branded.
|
|
549
|
+
*/
|
|
550
|
+
interface SelfRef {
|
|
551
|
+
readonly [SELF_REF]: true;
|
|
552
|
+
/** The self (view / relation-target) field name (e.g. `latestPosts`). */
|
|
553
|
+
readonly field: string;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* The typed `source` accessor handed to a `(self, source) =>` callback: one
|
|
557
|
+
* {@link SourceRef} per field of the source entity, each typed with the field's
|
|
558
|
+
* declared value type (so `preview(source.body, n)` type-checks against a string
|
|
559
|
+
* field and a key-value position type-checks against the bound view-key field).
|
|
560
|
+
*
|
|
561
|
+
* @typeParam S - The source entity instance type.
|
|
562
|
+
*/
|
|
563
|
+
type SourceProxy<S> = [unknown] extends [S] ? Readonly<Record<string, SourceRef>> : {
|
|
564
|
+
readonly [K in keyof S]-?: SourceRef & {
|
|
565
|
+
readonly __value?: S[K];
|
|
566
|
+
};
|
|
567
|
+
};
|
|
568
|
+
/**
|
|
569
|
+
* The typed `self` accessor handed to a `(self, source) =>` callback: one
|
|
570
|
+
* {@link SelfRef} per field of the model being defined. Used in the value position
|
|
571
|
+
* of `collection.field` (which self attribute holds the maintained collection).
|
|
572
|
+
*
|
|
573
|
+
* @typeParam T - The model (view / relation-target) instance type.
|
|
574
|
+
*/
|
|
575
|
+
type SelfProxy<T> = [unknown] extends [T] ? Readonly<Record<string, SelfRef>> : {
|
|
576
|
+
readonly [K in keyof T]-?: SelfRef & {
|
|
577
|
+
readonly __value?: T[K];
|
|
578
|
+
};
|
|
579
|
+
};
|
|
580
|
+
/**
|
|
581
|
+
* A projected value in a maintained `project` map: either a {@link SourceRef}
|
|
582
|
+
* (identity capture of a source field) or an explicit {@link ProjectionTransform}
|
|
583
|
+
* (e.g. `preview(source.body, 120)`). This is the value side of the "key = name,
|
|
584
|
+
* value = reference" rule; the key side is a `keyof Self` string literal.
|
|
585
|
+
*/
|
|
586
|
+
type ProjectionValue = SourceRef | ProjectionTransform;
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* `@maintainedFrom` — the class-level, decorator-declarative view authoring of
|
|
590
|
+
* issue #152 (the Contract-layer replacement for `defineView` / `ViewRegistry`).
|
|
591
|
+
*
|
|
592
|
+
* ## What it is
|
|
593
|
+
*
|
|
594
|
+
* A maintained **view** (`@model({ kind: 'materializedView' | 'sparseView' })`) is
|
|
595
|
+
* its own modelled row maintained from the lifecycle events of one or more source
|
|
596
|
+
* entities. Each source contributes via a CLASS-LEVEL `@maintainedFrom` decorator
|
|
597
|
+
* (stackable — multiple sources each fill different view fields). This is the
|
|
598
|
+
* `@model`/`@hasMany` collector流儀: each `@maintainedFrom` pushes a
|
|
599
|
+
* {@link MaintainedFromMetadata} into a module-level collector and `@model` drains
|
|
600
|
+
* it into `EntityMetadata.maintainedFrom`.
|
|
601
|
+
*
|
|
602
|
+
* ## Symbolic `(self, source) =>` evaluation (existing-mechanism reuse)
|
|
603
|
+
*
|
|
604
|
+
* The options are authored as a `(self, source) => ({...})` callback evaluated
|
|
605
|
+
* eagerly at decoration time with the SAME Proxy-sentinel mechanism `key()`/`gsi()`
|
|
606
|
+
* use (`src/decorators/maintained-symbolic.ts`):
|
|
607
|
+
*
|
|
608
|
+
* - `source.<field>` → a {@link SourceRef} (value position) lowering to
|
|
609
|
+
* `$.entity.<field>` — the exact path the old string builder produced, so the IR
|
|
610
|
+
* is byte-identical.
|
|
611
|
+
* - `self.<field>` → a {@link SelfRef} naming a view field (the `collection.field`
|
|
612
|
+
* position).
|
|
613
|
+
* - Object KEYS (`keyBind` / `project` left-hand side) stay `keyof Self` string
|
|
614
|
+
* literals (NOT computed keys).
|
|
615
|
+
* - `on: ['created' | 'updated' | 'removed'][]` — the source is the decorator's
|
|
616
|
+
* first argument, so the `'Post.created'` logical-name string is gone (the bug
|
|
617
|
+
* class #124/#130 hit is removed by construction).
|
|
618
|
+
*
|
|
619
|
+
* ## Order independence (issue #152 hardening)
|
|
620
|
+
*
|
|
621
|
+
* Stacking order carries NO meaning. The adapter
|
|
622
|
+
* (`src/relation/maintenance-view-adapter.ts`) rejects — at build time, loudly and
|
|
623
|
+
* symmetrically (same error whichever order the decorators are stacked) — any two
|
|
624
|
+
* `@maintainedFrom` declarations that write the SAME projection target, the SAME
|
|
625
|
+
* `collection.field`, or bind the SAME view-key field inconsistently. A legitimate
|
|
626
|
+
* multi-source view (different sources filling DIFFERENT fields) is fine.
|
|
627
|
+
*/
|
|
628
|
+
|
|
629
|
+
type AnyModelClass$1 = new (...args: any[]) => any;
|
|
630
|
+
type SourceFactory = () => AnyModelClass$1;
|
|
631
|
+
/**
|
|
632
|
+
* A map keyed by `keyof Self` (the typed view fields) with value type `V`. When
|
|
633
|
+
* `Self` is left at its `unknown` default (the un-annotated decorator), it widens to
|
|
634
|
+
* a permissive `Record<string, V>` so authoring works without an explicit generic;
|
|
635
|
+
* supply `Self` to get `keyof Self` key-name checking.
|
|
636
|
+
*/
|
|
637
|
+
type SelfKeyed<Self, V> = [unknown] extends [Self] ? Readonly<Record<string, V>> : {
|
|
638
|
+
readonly [K in keyof Self]?: V;
|
|
639
|
+
};
|
|
640
|
+
/**
|
|
641
|
+
* The author-facing options object a `@maintainedFrom` callback returns. Keys
|
|
642
|
+
* (`keyBind` / `project` left-hand side) are `keyof Self` string literals; values
|
|
643
|
+
* are symbolic {@link SourceRef} (`source.<field>`) / transforms / {@link SelfRef}
|
|
644
|
+
* (`self.<field>`). `collection` and `when` are mutually exclusive.
|
|
645
|
+
*
|
|
646
|
+
* @typeParam Self - The view model instance type (drives `keyof Self` keys).
|
|
647
|
+
*/
|
|
648
|
+
interface MaintainedFromOptions<Self = unknown> {
|
|
649
|
+
/** The lifecycle events of the source that maintain the view row. */
|
|
650
|
+
readonly on: readonly MaintainEvent[];
|
|
651
|
+
/**
|
|
652
|
+
* The view-row key binding: view-row key field (`keyof Self`) → a `source.<field>`
|
|
653
|
+
* reference resolving which view row this source event maintains.
|
|
654
|
+
*/
|
|
655
|
+
readonly keyBind: SelfKeyed<Self, SourceRef>;
|
|
656
|
+
/**
|
|
657
|
+
* The projection of the source payload into the view row: target attribute
|
|
658
|
+
* (`keyof Self`) → a `source.<field>` reference or a transform (`preview(...)`).
|
|
659
|
+
*/
|
|
660
|
+
readonly project: SelfKeyed<Self, ProjectionValue>;
|
|
661
|
+
/**
|
|
662
|
+
* Declares this source maintains a bounded, ordered COLLECTION slice of the view
|
|
663
|
+
* row. `field` is a `self.<field>` reference (which view attribute holds the
|
|
664
|
+
* list); `orderBy` is a `source.<field>` reference. Mutually exclusive with `when`.
|
|
665
|
+
*/
|
|
666
|
+
readonly collection?: {
|
|
667
|
+
readonly field: SelfRef;
|
|
668
|
+
readonly maxItems?: number;
|
|
669
|
+
readonly order?: 'ASC' | 'DESC';
|
|
670
|
+
readonly orderBy?: SourceRef;
|
|
671
|
+
};
|
|
672
|
+
/** Sparse-view membership predicate (sparseView kind). Mutually exclusive with `collection`. */
|
|
673
|
+
readonly when?: MembershipPredicate;
|
|
674
|
+
readonly consistency?: MaintainConsistency;
|
|
675
|
+
readonly updateMode?: MaintainUpdateMode;
|
|
676
|
+
}
|
|
677
|
+
/** The `(self, source) =>` symbolic callback evaluated at decoration time. */
|
|
678
|
+
type MaintainedFromCallback<Self, Source> = (self: SelfProxy<Self>, source: SourceProxy<Source>) => MaintainedFromOptions<Self>;
|
|
679
|
+
/**
|
|
680
|
+
* Build a {@link MembershipPredicate} for a sparse view. The view row is PUT when
|
|
681
|
+
* the predicate holds and DELETED when it flips false. The operand is a symbolic
|
|
682
|
+
* `source.<field>` reference (or a bare path string) lowered to `$.entity.<field>`.
|
|
683
|
+
*
|
|
684
|
+
* Named `whenMember` (not `when`) to avoid colliding with the transaction-condition
|
|
685
|
+
* `when` helper.
|
|
686
|
+
*
|
|
687
|
+
* @example `whenMember(source.status, 'eq', 'active')`
|
|
688
|
+
* @example `whenMember(source.archived, 'falsy')`
|
|
689
|
+
*/
|
|
690
|
+
declare function whenMember(operand: SourceRef | string, op: MembershipPredicateOp, value?: unknown): MembershipPredicate;
|
|
691
|
+
/**
|
|
692
|
+
* `@maintainedFrom(source, (self, source) => options)` — the class-level view
|
|
693
|
+
* maintainer decorator (issue #152). Stackable: apply once per source. Evaluates
|
|
694
|
+
* the symbolic callback at decoration time and records the lowered
|
|
695
|
+
* {@link MaintainedFromMetadata} into the collector for `@model` to drain.
|
|
696
|
+
*
|
|
697
|
+
* @typeParam Self - The view model instance type (typed `keyof Self` keys).
|
|
698
|
+
* @typeParam Source - The source entity instance type (typed `source.<field>`).
|
|
699
|
+
*
|
|
700
|
+
* @example
|
|
701
|
+
* ```ts
|
|
702
|
+
* @model({ table: 'AppTable', kind: 'materializedView' })
|
|
703
|
+
* @maintainedFrom(() => PostModel, (self, source) => ({
|
|
704
|
+
* keyBind: { userId: source.authorId, threadId: source.threadId },
|
|
705
|
+
* on: ['created', 'removed'],
|
|
706
|
+
* project: { lastPostAt: source.createdAt, textPreview: preview(source.body, 120) },
|
|
707
|
+
* collection: { field: self.latestPosts, orderBy: source.createdAt, order: 'DESC', maxItems: 20 },
|
|
708
|
+
* }))
|
|
709
|
+
* class UserThreadListModel extends DDBModel { … }
|
|
710
|
+
* ```
|
|
711
|
+
*/
|
|
712
|
+
declare function maintainedFrom<Self = unknown, Source = unknown>(source: SourceFactory, callback: MaintainedFromCallback<Self, Source>): (target: Function, context: ClassDecoratorContext) => void;
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Versioned relation `pattern` discriminated union (issue #152, section B).
|
|
716
|
+
*
|
|
717
|
+
* Versioned is "a preset that re-uses the core snapshot effect", so it rides on the
|
|
718
|
+
* `@hasOne` / `@hasMany` `pattern` discriminator instead of a dedicated decorator:
|
|
719
|
+
*
|
|
720
|
+
* - `@hasOne(() => Latest, (self, source) => ({ pattern: 'versionedLatest', on, project }))`
|
|
721
|
+
* — a SINGLE maintained row, OVERWRITTEN per revision (keyed without the version).
|
|
722
|
+
* - `@hasMany(() => History, (self, source) => ({ pattern: 'versionedHistory', on, project }))`
|
|
723
|
+
* — one APPENDED row per revision (keyed WITH the version).
|
|
724
|
+
*
|
|
725
|
+
* ## Three type-level guards (issue #152 B (a)/(b)/(c))
|
|
726
|
+
*
|
|
727
|
+
* (a) Per-pattern fields — the options union is discriminated on `pattern`, so each
|
|
728
|
+
* member admits exactly its own fields.
|
|
729
|
+
* (b) Cardinality integrity — `versionedLatest` is only assignable to a `@hasOne`
|
|
730
|
+
* callback's return and `versionedHistory` only to `@hasMany`'s, enforced by the
|
|
731
|
+
* distinct callback option types {@link HasOneVersionedOptions} /
|
|
732
|
+
* {@link HasManyVersionedOptions} the two decorators accept.
|
|
733
|
+
* (c) Symbolic refs — `source.<field>` is `keyof Source` and `project` keys are
|
|
734
|
+
* `keyof Self`, via the shared {@link SourceProxy} / proxy-sentinel mechanism.
|
|
735
|
+
*
|
|
736
|
+
* Both lower to the SAME snapshot×2 IR the old `defineVersioned` produced (the
|
|
737
|
+
* adapter `src/relation/maintenance-view-adapter.ts` turns the recorded
|
|
738
|
+
* `RelationOptions.versioned` into `defineView`-shaped `ViewDefinition`s). The
|
|
739
|
+
* latest/history KEY binding is derived from the TARGET model's own key input fields
|
|
740
|
+
* (each bound from the same-named source field) — latest keys omit the version,
|
|
741
|
+
* history keys include it, by the two models' own `key` definitions.
|
|
742
|
+
*/
|
|
743
|
+
|
|
744
|
+
/** A versioned-latest options object (single overwritten row). */
|
|
745
|
+
interface VersionedLatestOptions<Self = unknown> {
|
|
746
|
+
readonly pattern: 'versionedLatest';
|
|
747
|
+
readonly on: readonly MaintainEvent[];
|
|
748
|
+
readonly project: SelfKeyed<Self, ProjectionValue>;
|
|
749
|
+
readonly consistency?: MaintainConsistency;
|
|
750
|
+
readonly updateMode?: MaintainUpdateMode;
|
|
751
|
+
}
|
|
752
|
+
/** A versioned-history options object (append-only per-revision rows). */
|
|
753
|
+
interface VersionedHistoryOptions<Self = unknown> {
|
|
754
|
+
readonly pattern: 'versionedHistory';
|
|
755
|
+
readonly on: readonly MaintainEvent[];
|
|
756
|
+
readonly project: SelfKeyed<Self, ProjectionValue>;
|
|
757
|
+
readonly consistency?: MaintainConsistency;
|
|
758
|
+
readonly updateMode?: MaintainUpdateMode;
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* The options a `@hasOne` versioned callback may return — `versionedLatest` ONLY.
|
|
762
|
+
* (Cardinality integrity: a `versionedHistory` on `@hasOne` is a type error.)
|
|
763
|
+
*/
|
|
764
|
+
type HasOneVersionedOptions<Self = unknown> = VersionedLatestOptions<Self>;
|
|
765
|
+
/**
|
|
766
|
+
* The options a `@hasMany` versioned callback may return — `versionedHistory` ONLY.
|
|
767
|
+
* (Cardinality integrity: a `versionedLatest` on `@hasMany` is a type error.)
|
|
768
|
+
*/
|
|
769
|
+
type HasManyVersionedOptions<Self = unknown> = VersionedHistoryOptions<Self>;
|
|
770
|
+
/** The `(self, source) =>` versioned callback for `@hasOne`. */
|
|
771
|
+
type HasOneVersionedCallback<Self, Source> = (self: SelfProxy<Self>, source: SourceProxy<Source>) => HasOneVersionedOptions<Self>;
|
|
772
|
+
/** The `(self, source) =>` versioned callback for `@hasMany`. */
|
|
773
|
+
type HasManyVersionedCallback<Self, Source> = (self: SelfProxy<Self>, source: SourceProxy<Source>) => HasManyVersionedOptions<Self>;
|
|
774
|
+
|
|
775
|
+
declare function hasMany(targetFactory: () => new (...args: unknown[]) => unknown, keyBinding: Record<string, string>, options?: RelationOptions): (value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
776
|
+
declare function hasMany<Self = unknown, Source = unknown>(targetFactory: () => new (...args: unknown[]) => unknown, callback: HasManyVersionedCallback<Self, Source>): (value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
485
777
|
declare function belongsTo(targetFactory: () => new (...args: unknown[]) => unknown, keyBinding: Record<string, string>, options?: RelationOptions): (_value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
486
|
-
declare function hasOne(targetFactory: () => new (...args: unknown[]) => unknown, keyBinding: Record<string, string>): (
|
|
778
|
+
declare function hasOne(targetFactory: () => new (...args: unknown[]) => unknown, keyBinding: Record<string, string>): (value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
779
|
+
declare function hasOne<Self = unknown, Source = unknown>(targetFactory: () => new (...args: unknown[]) => unknown, callback: HasOneVersionedCallback<Self, Source>): (value: undefined, context: ClassFieldDecoratorContext) => void;
|
|
487
780
|
|
|
488
781
|
/**
|
|
489
782
|
* `@aggregate` — a **scalar-aggregate** field decorator (Epic #118 §5.2 counter /
|
|
@@ -1075,6 +1368,147 @@ declare class CdcEmulator {
|
|
|
1075
1368
|
/** Create a CDC emulator (spec §10). */
|
|
1076
1369
|
declare function createCdcEmulator(opts?: CdcEmulatorOptions): CdcEmulator;
|
|
1077
1370
|
|
|
1371
|
+
/**
|
|
1372
|
+
* CDC **maintenance drain** (issue #130) — the asynchronous lower for
|
|
1373
|
+
* `updateMode: 'stream'` maintainers (Epic #118 §5.1).
|
|
1374
|
+
*
|
|
1375
|
+
* A synchronous (`updateMode: 'mutation'`) maintainer composes its owner-row write
|
|
1376
|
+
* into the SAME atomic `TransactWriteItems` as the source write (#127). A
|
|
1377
|
+
* `updateMode: 'stream'` maintainer instead emits a **maintenance-outbox** marker row
|
|
1378
|
+
* (`OUTBOX#MAINT#…`) ATOMICALLY with the source write (the #130 compile lowering in
|
|
1379
|
+
* `src/spec/mutation-command.ts`), and THIS consumer — driven by the {@link
|
|
1380
|
+
* import('./emulator.js').CdcEmulator} (or, in production, real DynamoDB Streams +
|
|
1381
|
+
* a Lambda built around {@link createMaintenanceDrainHandler}) — applies the owner-row
|
|
1382
|
+
* write asynchronously.
|
|
1383
|
+
*
|
|
1384
|
+
* ## Why a separate async path exists (not just "do it later synchronously")
|
|
1385
|
+
*
|
|
1386
|
+
* The async path realizes the maintenance operations a single synchronous
|
|
1387
|
+
* `UpdateExpression` cannot express against an unread item:
|
|
1388
|
+
*
|
|
1389
|
+
* - **collection `maxItems` trim** — keeping a bounded, ordered list requires reading
|
|
1390
|
+
* the current list, appending, sorting, and trimming (a read-modify-write); a
|
|
1391
|
+
* synchronous `list_append` can only append (Phase 1 was append-only, #127).
|
|
1392
|
+
* - **`removed`-driven splice** — removing an entry from a maintained collection on a
|
|
1393
|
+
* source `removed` event likewise needs the current list.
|
|
1394
|
+
* - **running `max(field)`** — a conditional `SET` (`#a = :v` guarded by
|
|
1395
|
+
* `attribute_not_exists(#a) OR #a < :v`) whose failed guard, if run synchronously,
|
|
1396
|
+
* would roll back the legitimate source write.
|
|
1397
|
+
*
|
|
1398
|
+
* ## Delivery guarantees (reused from the CDC substrate)
|
|
1399
|
+
*
|
|
1400
|
+
* The maintenance-outbox row is recorded ATOMICALLY with the source write, so the
|
|
1401
|
+
* intent can never be lost ("wrote the row, lost the maintenance" is impossible). The
|
|
1402
|
+
* CDC substrate then delivers it **at-least-once**, **per-shard ordered** (a shard is
|
|
1403
|
+
* `hash(pk)`, and the outbox row's `pk` is keyed off the SOURCE row's key, so all
|
|
1404
|
+
* maintenance events for one source entity land on one shard in source-write order),
|
|
1405
|
+
* with a **DLQ** for poison events. This consumer is therefore written to be
|
|
1406
|
+
* **idempotent / commutative** wherever at-least-once redelivery could double-apply:
|
|
1407
|
+
*
|
|
1408
|
+
* - a `snapshot` `SET` is naturally idempotent (re-applying the same projection is a
|
|
1409
|
+
* no-op);
|
|
1410
|
+
* - a `collection` rebuild de-duplicates by the projected item's identity key, so a
|
|
1411
|
+
* redelivered append does not grow the list twice;
|
|
1412
|
+
* - a `max` conditional `SET` is idempotent (the guard rejects a non-greater value);
|
|
1413
|
+
* - a `count` `ADD` is the ONE non-idempotent op — but the source-row create guard
|
|
1414
|
+
* (`attribute_not_exists`) means a given source `created` event is emitted at most
|
|
1415
|
+
* once into the outbox, and the per-shard checkpoint advances only over acked events,
|
|
1416
|
+
* so a `count` is applied once per genuine source lifecycle. (A duplicate DELIVERY of
|
|
1417
|
+
* the same event is folded by the consumer's per-event de-dup set within a drain.)
|
|
1418
|
+
*/
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* The PK prefix a maintenance-outbox row keys on — the single source of truth shared
|
|
1422
|
+
* with the compiler ({@link import('../spec/mutation-command.js')}'s
|
|
1423
|
+
* `MAINT_OUTBOX_PK_PREFIX`). The drain selects its events by `keys.pk.startsWith` of
|
|
1424
|
+
* this. Kept as a local literal (rather than importing a non-exported compiler const)
|
|
1425
|
+
* so the cdc module does not depend on the spec module; the value is asserted equal by
|
|
1426
|
+
* the integration tests that round-trip a real stream maintainer through both.
|
|
1427
|
+
*/
|
|
1428
|
+
declare const MAINT_OUTBOX_PK_PREFIX = "OUTBOX#MAINT#";
|
|
1429
|
+
/** Options for {@link createMaintenanceDrain}. */
|
|
1430
|
+
interface MaintenanceDrainOptions {
|
|
1431
|
+
/**
|
|
1432
|
+
* The model classes (or `ModelStatic`s) whose stream maintainers this drain
|
|
1433
|
+
* applies. The drain builds a scoped {@link MaintenanceGraph} over them to resolve
|
|
1434
|
+
* each maintenance-outbox event back to its declared effect. Defaults to the GLOBAL
|
|
1435
|
+
* registry when omitted.
|
|
1436
|
+
*/
|
|
1437
|
+
readonly models?: readonly Function[];
|
|
1438
|
+
/**
|
|
1439
|
+
* The {@link ViewDefinition}s (`defineView`) whose maintainers this drain applies
|
|
1440
|
+
* (issue #132). A view's destination is its dedicated view model; its source
|
|
1441
|
+
* classes should also be in {@link models} so the drain can resolve their
|
|
1442
|
+
* maintenance-outbox events. Defaults to none.
|
|
1443
|
+
*/
|
|
1444
|
+
readonly views?: readonly ViewDefinition[];
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* A maintenance drain: a CDC consumer ({@link ChangeHandler}) that applies the
|
|
1448
|
+
* owner-row writes for `updateMode: 'stream'` maintainers. Construct via
|
|
1449
|
+
* {@link createMaintenanceDrain}, then `subscribe` its {@link handler} to a
|
|
1450
|
+
* {@link import('./emulator.js').CdcEmulator} (dev/test) or wire it into a real
|
|
1451
|
+
* Streams Lambda (production).
|
|
1452
|
+
*/
|
|
1453
|
+
declare class MaintenanceDrain {
|
|
1454
|
+
private readonly graph;
|
|
1455
|
+
/** Owner entity name → its model class (for the owner-row key derivation). */
|
|
1456
|
+
private readonly ownerByName;
|
|
1457
|
+
/** Per-event-id de-dup within a single handler invocation (at-least-once). */
|
|
1458
|
+
private appliedSeq;
|
|
1459
|
+
/** Count of owner-row writes applied (test/diagnostic). */
|
|
1460
|
+
private applied;
|
|
1461
|
+
constructor(opts?: MaintenanceDrainOptions);
|
|
1462
|
+
/** The CDC {@link ChangeHandler} to subscribe to an emulator / Streams source. */
|
|
1463
|
+
readonly handler: ChangeHandler;
|
|
1464
|
+
/** Resolve one maintenance-outbox event to its effect and apply the owner-row write. */
|
|
1465
|
+
private applyOne;
|
|
1466
|
+
/** Resolve a maintenance-outbox event back to the declared {@link MaintainItem}. */
|
|
1467
|
+
private resolve;
|
|
1468
|
+
/** A `snapshot` SET of each projected attribute onto the owner row (idempotent). */
|
|
1469
|
+
private applySnapshot;
|
|
1470
|
+
/**
|
|
1471
|
+
* A sparse-view **membership** write (#133): evaluate the membership predicate against
|
|
1472
|
+
* the source image; PUT the view row (its projection + key fields) when the predicate
|
|
1473
|
+
* holds, DELETE it when it flips false. A source `removed` event always deletes (the
|
|
1474
|
+
* source no longer exists, so its view row must disappear regardless of the predicate).
|
|
1475
|
+
*
|
|
1476
|
+
* Both ops are idempotent under at-least-once redelivery: a repeated PUT writes the same
|
|
1477
|
+
* row, a repeated DELETE is a no-op. The view row is keyed by the source identity
|
|
1478
|
+
* (`effect.keys`), so the PUT/DELETE always targets the SAME physical row the predicate
|
|
1479
|
+
* gates.
|
|
1480
|
+
*/
|
|
1481
|
+
private applyMembership;
|
|
1482
|
+
/**
|
|
1483
|
+
* A running `max`: read the owner row, and `SET` the attribute to the source value
|
|
1484
|
+
* only when it is greater (or absent). Implemented as a conditional update so a
|
|
1485
|
+
* redelivered / out-of-order older value never regresses the stored max — idempotent
|
|
1486
|
+
* and commutative under at-least-once delivery.
|
|
1487
|
+
*/
|
|
1488
|
+
private applyMax;
|
|
1489
|
+
/**
|
|
1490
|
+
* A bounded `collection`: read the current list, apply the event (append for a
|
|
1491
|
+
* `created`/`updated` source, splice for a `removed`), de-duplicate by the projected
|
|
1492
|
+
* identity key, order by `orderBy` (in `orderDir`, default DESC), trim to `maxItems`, and write the whole
|
|
1493
|
+
* list back. The read-modify-write is exactly what a single synchronous
|
|
1494
|
+
* `UpdateExpression` cannot do — the reason a bounded/ordered collection is a stream
|
|
1495
|
+
* maintainer (Phase 1 sync was append-only).
|
|
1496
|
+
*/
|
|
1497
|
+
private applyCollection;
|
|
1498
|
+
/** Owner-row writes applied so far (test/diagnostic). */
|
|
1499
|
+
appliedCount(): number;
|
|
1500
|
+
/** Clear the per-delivery de-dup set + counters (test reset). */
|
|
1501
|
+
reset(): void;
|
|
1502
|
+
}
|
|
1503
|
+
/** Create a {@link MaintenanceDrain} (issue #130). */
|
|
1504
|
+
declare function createMaintenanceDrain(opts?: MaintenanceDrainOptions): MaintenanceDrain;
|
|
1505
|
+
/**
|
|
1506
|
+
* Create just the CDC {@link ChangeHandler} for a maintenance drain — the form to
|
|
1507
|
+
* subscribe to an emulator or wire into a production Streams Lambda. A thin wrapper
|
|
1508
|
+
* over {@link createMaintenanceDrain} for callers that only need the handler.
|
|
1509
|
+
*/
|
|
1510
|
+
declare function createMaintenanceDrainHandler(opts?: MaintenanceDrainOptions): ChangeHandler;
|
|
1511
|
+
|
|
1078
1512
|
/**
|
|
1079
1513
|
* Per-key cursor envelope for batched `range` (`list`) contract methods (issue
|
|
1080
1514
|
* #62, CQRS single-service runtime; spec `docs/cqrs-contract.md`,
|
|
@@ -1340,12 +1774,42 @@ type EdgeLifecycle = 'onCreate' | 'onDelete' | 'onUpdateKeyChange';
|
|
|
1340
1774
|
* lifecycle-agnostic — the *same* edge is created on create, deleted on delete,
|
|
1341
1775
|
* and moved on a foreign-key change; {@link deriveEdgeWriteItems} fans it out
|
|
1342
1776
|
* into the three lifecycle forms.
|
|
1777
|
+
*
|
|
1778
|
+
* ## `inverse` — dual-edge synchronization (Epic #118 pattern 9, issue #133)
|
|
1779
|
+
*
|
|
1780
|
+
* The plain edge above is **one physical row** that serves *both* read directions:
|
|
1781
|
+
* the base PK reads one direction and an inverse GSI (auto-maintained by DynamoDB)
|
|
1782
|
+
* reads the other, so a bidirectional relation costs a single write. The RFC §1
|
|
1783
|
+
* pattern-9 gap is the case where the inverse direction is NOT served by that GSI
|
|
1784
|
+
* but by a **second physical row** on its own partition — the genuine *dual edge*
|
|
1785
|
+
* (forward + inverse rows). {@link inverse}, when present, names a SECOND adjacency
|
|
1786
|
+
* model + relation property whose row is the inverse edge; {@link
|
|
1787
|
+
* deriveEdgeWriteItemsFor} then maintains BOTH rows from this single (one-direction)
|
|
1788
|
+
* declaration — the create `Put`s both, the delete `Delete`s both, a foreign-key
|
|
1789
|
+
* change `Delete`s+`Put`s both — so the two directions can never drift. Omit
|
|
1790
|
+
* `inverse` for the historical single-row-plus-GSI bidirectional edge.
|
|
1343
1791
|
*/
|
|
1344
1792
|
interface EdgeWriteDeclaration {
|
|
1345
1793
|
/** Resolves the target model whose relation this edge feeds (e.g. `GroupModel`). */
|
|
1346
1794
|
readonly targetFactory: () => new (...args: unknown[]) => unknown;
|
|
1347
1795
|
/** The relation property on the target that reads this edge (e.g. `members`). */
|
|
1348
1796
|
readonly relationProperty: string;
|
|
1797
|
+
/**
|
|
1798
|
+
* The INVERSE edge to keep in sync (Epic #118 pattern 9 / issue #133, dual-edge).
|
|
1799
|
+
* Names the second adjacency model whose own row materializes the reverse-direction
|
|
1800
|
+
* relation. When present, every lifecycle derivation maintains the inverse row
|
|
1801
|
+
* alongside the forward row in the SAME transaction, so a one-direction declaration
|
|
1802
|
+
* keeps a two-row bidirectional edge consistent. Absent = the historical single-row
|
|
1803
|
+
* (base + inverse GSI) bidirectional edge.
|
|
1804
|
+
*/
|
|
1805
|
+
readonly inverse?: {
|
|
1806
|
+
/** Resolves the inverse adjacency model whose row IS the inverse edge. */
|
|
1807
|
+
readonly adjacencyFactory: () => new (...args: unknown[]) => unknown;
|
|
1808
|
+
/** Resolves the target model whose relation the inverse row feeds. */
|
|
1809
|
+
readonly targetFactory: () => new (...args: unknown[]) => unknown;
|
|
1810
|
+
/** The relation property on the inverse target that reads the inverse row. */
|
|
1811
|
+
readonly relationProperty: string;
|
|
1812
|
+
};
|
|
1349
1813
|
}
|
|
1350
1814
|
/**
|
|
1351
1815
|
* Marker carried by a model's static `writes` member ({@link edgeWrites}), so it
|
|
@@ -1386,6 +1850,34 @@ interface EdgeWriteRecorder {
|
|
|
1386
1850
|
* `relationProperty` relation (→ adjacency `Delete`(old) + `Put`(new)).
|
|
1387
1851
|
*/
|
|
1388
1852
|
updateKeyChangeEdge(target: () => new (...args: unknown[]) => unknown, relationProperty: string): EdgeWriteDeclaration;
|
|
1853
|
+
/**
|
|
1854
|
+
* Declare a **dual edge** (Epic #118 pattern 9 / issue #133): a bidirectional edge
|
|
1855
|
+
* maintained as TWO physical rows — a forward row on THIS adjacency entity (read by
|
|
1856
|
+
* `forward.target.relationProperty`) and an inverse row on a SECOND adjacency model
|
|
1857
|
+
* (read by `inverse.target.relationProperty`). Both rows are written / deleted /
|
|
1858
|
+
* moved together from this single declaration, so the two directions stay in sync
|
|
1859
|
+
* without an inverse GSI. Use this when the reverse direction lives on its own
|
|
1860
|
+
* partition (a second row) rather than a GSI of the forward row.
|
|
1861
|
+
*
|
|
1862
|
+
* @example
|
|
1863
|
+
* ```ts
|
|
1864
|
+
* // On the forward adjacency entity (FollowEdge: FOLLOWER#a / FOLLOWING#b):
|
|
1865
|
+
* static readonly writes = edgeWrites((w) => [
|
|
1866
|
+
* w.dualEdge(
|
|
1867
|
+
* { target: () => UserModel, relationProperty: 'following' },
|
|
1868
|
+
* { adjacency: () => FollowedByEdgeModel, target: () => UserModel, relationProperty: 'followers' },
|
|
1869
|
+
* ),
|
|
1870
|
+
* ]);
|
|
1871
|
+
* ```
|
|
1872
|
+
*/
|
|
1873
|
+
dualEdge(forward: {
|
|
1874
|
+
target: () => new (...args: unknown[]) => unknown;
|
|
1875
|
+
relationProperty: string;
|
|
1876
|
+
}, inverse: {
|
|
1877
|
+
adjacency: () => new (...args: unknown[]) => unknown;
|
|
1878
|
+
target: () => new (...args: unknown[]) => unknown;
|
|
1879
|
+
relationProperty: string;
|
|
1880
|
+
}): EdgeWriteDeclaration;
|
|
1389
1881
|
}
|
|
1390
1882
|
/**
|
|
1391
1883
|
* Declare an adjacency entity's edge write side (issue #82), as the model's
|
|
@@ -1457,6 +1949,182 @@ declare function getEdgeWrites(modelClass: new (...args: unknown[]) => unknown):
|
|
|
1457
1949
|
*/
|
|
1458
1950
|
declare function deriveModelEdgeWriteItems(modelClass: new (...args: unknown[]) => unknown, lifecycle: EdgeLifecycle): TransactionItemSpec[];
|
|
1459
1951
|
|
|
1952
|
+
/**
|
|
1953
|
+
* Maintenance **repair / rebuild planner** (Epic #118 Phase 2, issue #131).
|
|
1954
|
+
*
|
|
1955
|
+
* ## What this is
|
|
1956
|
+
*
|
|
1957
|
+
* The async drain ({@link import('../cdc/maintenance-drain.js')}, #130) keeps a
|
|
1958
|
+
* maintained owner row (a snapshot / collection / counter) in sync INCREMENTALLY —
|
|
1959
|
+
* it applies one source event at a time. Over a long-lived table the materialized
|
|
1960
|
+
* value can nevertheless **drift** from the source of truth: a dropped / dead-lettered
|
|
1961
|
+
* stream event, a maintainer added AFTER source rows already existed (initial
|
|
1962
|
+
* un-built state), a bug in an earlier maintainer version, or an out-of-band write.
|
|
1963
|
+
*
|
|
1964
|
+
* The rebuild planner is the repair for that drift. For a given owner row × maintainer
|
|
1965
|
+
* it **re-derives the owner-row value from scratch by scanning every source row that
|
|
1966
|
+
* belongs to that owner**, using the SAME projection / aggregation / ordering rules the
|
|
1967
|
+
* drain uses (shared via `maintenance-projection.ts` and this module), then:
|
|
1968
|
+
*
|
|
1969
|
+
* - **{@link detectDrift}** — compares the re-derived value against the value currently
|
|
1970
|
+
* stored on the owner row and reports whether (and how) they differ; or
|
|
1971
|
+
* - **{@link rebuild}** — writes the re-derived ABSOLUTE value onto the owner row, so the
|
|
1972
|
+
* materialized data converges to exactly what the source says.
|
|
1973
|
+
*
|
|
1974
|
+
* After a rebuild the owner row equals what an incremental drain would have converged to
|
|
1975
|
+
* had it never missed an event — the AC: "rebuild で materialized が source と一致する".
|
|
1976
|
+
*
|
|
1977
|
+
* ## Granularity: per owner row × maintainer
|
|
1978
|
+
*
|
|
1979
|
+
* Drift is detected and repaired at the **owner-row × maintainer** grain — the natural
|
|
1980
|
+
* unit, because one owner row's materialized value is a pure function of the set of
|
|
1981
|
+
* source rows bound to it. The caller names the owner rows to repair (their key inputs);
|
|
1982
|
+
* the planner discovers the source rows for each by querying the source on the maintenance
|
|
1983
|
+
* key binding (the same binding the live `hasMany` / `@aggregate` read uses, inverted:
|
|
1984
|
+
* the owner row supplies the binding value, the source partition is scanned for matches).
|
|
1985
|
+
*
|
|
1986
|
+
* ## count is re-derived as an ABSOLUTE SET, not an ADD
|
|
1987
|
+
*
|
|
1988
|
+
* The maintained counter applies a signed `ADD` per event (#141 / #130). A rebuild
|
|
1989
|
+
* instead **counts the source rows and SETs the absolute value** — it does not trust the
|
|
1990
|
+
* accumulated counter, it recomputes it. This is the whole point of repair (an ADD that
|
|
1991
|
+
* has drifted cannot be corrected by another ADD). The `max(field)` counter is re-derived
|
|
1992
|
+
* as the maximum over the scanned source rows and SET unconditionally (the rebuild is the
|
|
1993
|
+
* authority, so it does not use the drain's advance-only conditional guard).
|
|
1994
|
+
*
|
|
1995
|
+
* ## Execution form (production positioning)
|
|
1996
|
+
*
|
|
1997
|
+
* Like the drain applier, this is a **TS-side planner/executor** intended for dev/test and
|
|
1998
|
+
* **operational repair tooling** — run on-demand (a "repair this thread's summary now"
|
|
1999
|
+
* admin action) or as a periodic batch (a scheduled reconciliation sweep over a set of
|
|
2000
|
+
* owner rows). It is NOT injected into the SSoT spec and emits no generated artifact: a
|
|
2001
|
+
* rebuild is a host-side reconciliation against live DynamoDB, not part of a model's
|
|
2002
|
+
* compiled write contract — so there is no Python mirror (the Python runtime executes the
|
|
2003
|
+
* generated contract; rebuild is not in it). It reuses the maintenance graph (#124) to
|
|
2004
|
+
* resolve which maintainers exist and the shared re-derivation rules so a rebuilt value is
|
|
2005
|
+
* byte-consistent with a drained one.
|
|
2006
|
+
*/
|
|
2007
|
+
|
|
2008
|
+
/** A model class (or `ModelStatic`) the rebuild planner operates over. */
|
|
2009
|
+
type ModelLike = Function | ModelStatic<DDBModel>;
|
|
2010
|
+
/** Options for {@link createMaintenanceRebuilder}. */
|
|
2011
|
+
interface MaintenanceRebuildOptions {
|
|
2012
|
+
/**
|
|
2013
|
+
* The model classes whose maintainers this rebuilder can repair. The rebuilder
|
|
2014
|
+
* builds a scoped {@link MaintenanceGraph} over them to resolve each
|
|
2015
|
+
* owner-row × maintainer back to its declared effect. Defaults to the GLOBAL
|
|
2016
|
+
* registry when omitted.
|
|
2017
|
+
*/
|
|
2018
|
+
readonly models?: readonly ModelLike[];
|
|
2019
|
+
/**
|
|
2020
|
+
* The {@link ViewDefinition}s (`defineView`) whose maintainers this rebuilder can
|
|
2021
|
+
* repair (issue #132). The view model classes are added to the scoped registry so a
|
|
2022
|
+
* view row can be re-derived from its source rows, exactly like a relation owner row.
|
|
2023
|
+
*/
|
|
2024
|
+
readonly views?: readonly ViewDefinition[];
|
|
2025
|
+
}
|
|
2026
|
+
/**
|
|
2027
|
+
* The drift verdict for one owner row × maintainer: whether the currently-stored
|
|
2028
|
+
* materialized value differs from the value re-derived from the source rows, and both
|
|
2029
|
+
* values (for diagnostics / a repair preview). `expected` is the re-derived authority;
|
|
2030
|
+
* `actual` is what the owner row currently holds (`undefined` when never built).
|
|
2031
|
+
*/
|
|
2032
|
+
interface DriftReport {
|
|
2033
|
+
/** The relation / aggregate property the maintained value lives under. */
|
|
2034
|
+
readonly relationProperty: string;
|
|
2035
|
+
/** The owner entity (logical name) the row belongs to. */
|
|
2036
|
+
readonly ownerEntity: string;
|
|
2037
|
+
/** The owner row's resolved key (`{ PK, SK }`). */
|
|
2038
|
+
readonly ownerKey: Record<string, unknown>;
|
|
2039
|
+
/** The maintained attribute (collection field / snapshot attrs / counter attribute). */
|
|
2040
|
+
readonly kind: MaintainEffect['kind'];
|
|
2041
|
+
/** True when `actual` differs from `expected` (drift present). */
|
|
2042
|
+
readonly drifted: boolean;
|
|
2043
|
+
/** The value re-derived from the source rows (the authority). */
|
|
2044
|
+
readonly expected: unknown;
|
|
2045
|
+
/** The value currently stored on the owner row (`undefined` when unbuilt). */
|
|
2046
|
+
readonly actual: unknown;
|
|
2047
|
+
}
|
|
2048
|
+
/** The outcome of a {@link MaintenanceRebuilder.rebuild} over one owner row × maintainer. */
|
|
2049
|
+
interface RebuildResult extends DriftReport {
|
|
2050
|
+
/** True when the owner row was written (drift was present and repaired). */
|
|
2051
|
+
readonly repaired: boolean;
|
|
2052
|
+
}
|
|
2053
|
+
/**
|
|
2054
|
+
* A maintenance **repair / rebuild planner** (#131). Construct via
|
|
2055
|
+
* {@link createMaintenanceRebuilder}, then call {@link detectDrift} to compare or
|
|
2056
|
+
* {@link rebuild} to repair one owner row × maintainer (resolved by the owner model +
|
|
2057
|
+
* the relation/aggregate property + the owner key inputs).
|
|
2058
|
+
*/
|
|
2059
|
+
declare class MaintenanceRebuilder {
|
|
2060
|
+
private readonly graph;
|
|
2061
|
+
constructor(opts?: MaintenanceRebuildOptions);
|
|
2062
|
+
/**
|
|
2063
|
+
* Re-derive the materialized value for one owner row × maintainer from the source
|
|
2064
|
+
* rows and report whether it differs from what the owner row currently stores. Does
|
|
2065
|
+
* NOT write anything (a read-only drift probe).
|
|
2066
|
+
*
|
|
2067
|
+
* @param owner The owner model class declaring the maintainer.
|
|
2068
|
+
* @param relationProperty The relation / `@aggregate` property the value lives under.
|
|
2069
|
+
* @param ownerKeyInput The owner row's key input (e.g. `{ threadId: 't1' }`).
|
|
2070
|
+
*/
|
|
2071
|
+
detectDrift(owner: ModelLike, relationProperty: string, ownerKeyInput: Record<string, unknown>): Promise<DriftReport>;
|
|
2072
|
+
/**
|
|
2073
|
+
* Re-derive the materialized value for one owner row × maintainer from the source
|
|
2074
|
+
* rows and WRITE the absolute re-derived value onto the owner row when it drifts (or
|
|
2075
|
+
* always, when `force`). Returns the drift verdict plus whether a repair write ran.
|
|
2076
|
+
*
|
|
2077
|
+
* @param options.force Write even when no drift is detected (default: write only on drift).
|
|
2078
|
+
*/
|
|
2079
|
+
rebuild(owner: ModelLike, relationProperty: string, ownerKeyInput: Record<string, unknown>, options?: {
|
|
2080
|
+
force?: boolean;
|
|
2081
|
+
}): Promise<RebuildResult>;
|
|
2082
|
+
/** Resolve an owner model + property to its {@link MaintainItem} + owner-key builder. */
|
|
2083
|
+
private resolve;
|
|
2084
|
+
/**
|
|
2085
|
+
* Scan every source row bound to this owner row and re-derive the maintained value:
|
|
2086
|
+
*
|
|
2087
|
+
* - **collection** — project each source row, order + trim by the SAME read-side
|
|
2088
|
+
* rules (`orderBy` / `orderDir` / `maxItems`) the drain uses, return the list;
|
|
2089
|
+
* - **snapshot** — project the single bound source row (or `undefined` when none);
|
|
2090
|
+
* - **counter `count`** — the COUNT of source rows (absolute, not an ADD);
|
|
2091
|
+
* - **counter `max`** — the maximum source value of the tracked field.
|
|
2092
|
+
*/
|
|
2093
|
+
private recompute;
|
|
2094
|
+
/**
|
|
2095
|
+
* The source rows bound to one owner row. The maintenance key binding is
|
|
2096
|
+
* `{ ownerField: '$.entity.<sourceField>' }` (the destination owner-key field ← the
|
|
2097
|
+
* source row's field). INVERTED for a rebuild: the owner row supplies the value, and
|
|
2098
|
+
* the source partition is queried for rows whose `<sourceField>` matches — exactly the
|
|
2099
|
+
* set the live `hasMany` / `@aggregate` read aggregates. Queries the source via the
|
|
2100
|
+
* same {@link plan} the read planner uses (a partition Query), paginating fully.
|
|
2101
|
+
*/
|
|
2102
|
+
private scanSourceRows;
|
|
2103
|
+
/** Re-derive a bounded collection: project, then order + trim by the read-side rules. */
|
|
2104
|
+
private recomputeCollection;
|
|
2105
|
+
/**
|
|
2106
|
+
* Re-derive a single-row snapshot. A snapshot mirrors ONE source row (a `belongsTo` /
|
|
2107
|
+
* `hasOne`, normally 1:1). In the unusual case where MORE THAN ONE source row binds, the
|
|
2108
|
+
* live single-value read takes the FIRST row in the source's natural query order
|
|
2109
|
+
* (`ScanIndexForward`, default ASC = the smallest sort-key leaf), so re-derive the same
|
|
2110
|
+
* row — {@link pickFirst} — for a verdict consistent with the live read. Returns
|
|
2111
|
+
* `undefined` when no source row is bound (the snapshot should be absent).
|
|
2112
|
+
*/
|
|
2113
|
+
private recomputeSnapshot;
|
|
2114
|
+
/** The source entity metadata a maintain effect projects from (its relation target). */
|
|
2115
|
+
private sourceMetaOf;
|
|
2116
|
+
/** Re-derive a counter: the absolute COUNT of source rows, or the MAX of the tracked field. */
|
|
2117
|
+
private recomputeCounter;
|
|
2118
|
+
/** Read the owner row (consistent) for the drift comparison / actual value. */
|
|
2119
|
+
private readOwnerRow;
|
|
2120
|
+
/** The value currently stored on the owner row for this maintainer. */
|
|
2121
|
+
private actualValue;
|
|
2122
|
+
/** Write the re-derived ABSOLUTE value onto the owner row (the repair). */
|
|
2123
|
+
private writeValue;
|
|
2124
|
+
}
|
|
2125
|
+
/** Create a {@link MaintenanceRebuilder} (issue #131). */
|
|
2126
|
+
declare function createMaintenanceRebuilder(opts?: MaintenanceRebuildOptions): MaintenanceRebuilder;
|
|
2127
|
+
|
|
1460
2128
|
/**
|
|
1461
2129
|
* Type-level machinery for the parameterized definition DSL (issue #41).
|
|
1462
2130
|
*
|
|
@@ -2328,4 +2996,4 @@ declare function assertBundleSerializable(bundle: BridgeBundle): void;
|
|
|
2328
2996
|
*/
|
|
2329
2997
|
declare function buildBridgeBundle(queries?: DefinitionMap, commands?: DefinitionMap, registry?: typeof MetadataRegistry, transactions?: Record<string, TransactionDefinition>, contractInputs?: ContractInputs): BridgeBundle;
|
|
2330
2998
|
|
|
2331
|
-
export { AggregateOptions, AggregateValue, type AnyModelContract, AnyOperationDefinition, BATCH_GET_MAX_KEYS, BATCH_WRITE_MAX_ITEMS, BatchExecOptions, BatchGetExecInput, BatchWriteExecItem, BridgeBundle, type BuiltContracts, CdcEmulator, CdcEmulatorOptions, ChangeEvent, ChangeHandler, ClientManager, type CollectParams, CommandMethodSpec, CommandModelContract, CommandSpec, ConcurrentRecomputeRef, type ConditionExpressionResult, ConditionInput, ConditionSpec, type ContextOwnership, type ContextOwnershipMap, ContextSpec, type ContractBoundaryViolation, type ContractInputs, type ContractMap, type ContractN1Violation, ContractSpec, CtxModel, DDBModel, DefinitionMap, DeleteInput, DynamoDBOperation, DynamoExecutor, DynamoType, EDGE_WRITES_MARKER, type EdgeLifecycle, type EdgeWriteDeclaration, type EdgeWriteRecorder, type EdgeWritesDefinition, EntityMetadata, EntityRef, EventLog, ExecutionPlan, Executor, ExecutorResult, type ExplainInput, FaultSpec, FieldMetadata, FieldOptions, type FilterExpressionResult, GsiDefinition, Item, KeyDefinition, type LintResult, type LintRule, Linter, type ListInput, type ListOptions, MAX_TRANSACT_ITEMS, Manifest, MetadataRegistry, Middleware, type ModelOptions, ModelStatic, OLD_VALUE_NAMESPACE, OperationDefinition, OperationsDocument, Param, ParamDescriptor, type Parameterize, PartialQueryKeyOf, type PerKeyCursorEnvelope, type PlanInput, PrimaryKeyOf, type ProjectionResult, PutInput, QueryMethodSpec, QueryModelContract, type QueryOptions$1 as QueryOptions, QuerySpec, RawCondition, ReadExecOptions, ReadParams, ReadRequestCtx, ReadRequestKind, RelationMetadata, RelationOptions, type RelationTraversalOptions, ReplayOptions, RequestContext, ResolvedKey, RetryOverride, RetryPolicy, RetryingExecutor, SelectableOf, ShardId, TableMapping, TransactWriteExecItem, type TransactionDefinition, TransactionItemSpec, type TransactionParamShape, type TransactionRef, TransactionSpec, type TxConditionCheckOptions, type TxForEachInstruction, type TxForEachOptions, type TxInstruction, type TxRecorder, type TxWriteInstruction, type TxWriteOptions, UniqueQueryKeyOf, type UpdateExpressionResult, UpdateInput, type WhenComparison, WriteDefinitionOptions, WriteExecOptions, WriteResult, aggregate, assertBundleSerializable, assertContractBoundaries, assertContractN1Safe, assertJsonSerializable, assertSupportedCondition, belongsTo, binary, boolean, buildBridgeBundle, buildConditionExpression, buildContexts, buildContracts, buildManifest, buildOperations, buildProjection, buildQuerySpec, buildTransactionSpec, buildTransactions, buildUpdateExpression, collectContractBoundaryViolations, collectContractN1Violations, compileFilterExpression, count, createCdcEmulator, createDefaultLinter, datetime, decodeCursor, decodePerKeyCursor, defineCommands, defineDelete, defineList, definePut, defineQueries, defineQuery, defineTransaction, defineTransactions, defineUpdate, deriveEdgeWriteItems, deriveEdgeWriteItemsFor, deriveModelEdgeWriteItems, derivePrefix, detectRelationFields, edgeWrites, embedded, encodeCursor, encodePerKeyCursor, evaluateFilter, execute, executeDeclarativeTransaction, executeExplain, executeList, executeQuery, expandTransaction, field, getEdgeWrites, getImplicitKeyFields, gsiAmbiguityRule, hasMany, hasOne, hydrate, isEdgeWritesDefinition, isSelectBuilder, isTransactionRef, list, literal, map, max, missingGsiRule, model, noScanRule, number, numberSet, plan, queryBoundaryRule, relationDepthRule, requireLimitRule, resolveKey, resolveRelations, serializeContractKey, serializeFieldValue, string, stringSet, validateDepth, validateGsiAmbiguity, when };
|
|
2999
|
+
export { AggregateOptions, AggregateValue, type AnyModelContract, AnyOperationDefinition, BATCH_GET_MAX_KEYS, BATCH_WRITE_MAX_ITEMS, BatchExecOptions, BatchGetExecInput, BatchWriteExecItem, BridgeBundle, type BuiltContracts, CdcEmulator, CdcEmulatorOptions, ChangeEvent, ChangeHandler, ClientManager, type CollectParams, CommandMethodSpec, CommandModelContract, CommandSpec, ConcurrentRecomputeRef, type ConditionExpressionResult, ConditionInput, ConditionSpec, type ContextOwnership, type ContextOwnershipMap, ContextSpec, type ContractBoundaryViolation, type ContractInputs, type ContractMap, type ContractN1Violation, ContractSpec, CtxModel, DDBModel, DefinitionMap, DeleteInput, type DriftReport, DynamoDBOperation, DynamoExecutor, DynamoType, EDGE_WRITES_MARKER, type EdgeLifecycle, type EdgeWriteDeclaration, type EdgeWriteRecorder, type EdgeWritesDefinition, EntityMetadata, EntityRef, EventLog, ExecutionPlan, Executor, ExecutorResult, type ExplainInput, FaultSpec, FieldMetadata, FieldOptions, type FilterExpressionResult, GsiDefinition, type HasManyVersionedCallback, type HasManyVersionedOptions, type HasOneVersionedCallback, type HasOneVersionedOptions, Item, KeyDefinition, type LintResult, type LintRule, Linter, type ListInput, type ListOptions, MAINT_OUTBOX_PK_PREFIX, MAX_TRANSACT_ITEMS, MaintainConsistency, MaintainEffect, MaintainEvent, MaintainUpdateMode, type MaintainedFromCallback, type MaintainedFromOptions, MaintenanceDrain, type MaintenanceDrainOptions, type MaintenanceRebuildOptions, MaintenanceRebuilder, Manifest, MembershipPredicate, MembershipPredicateOp, MetadataRegistry, Middleware, type ModelOptions, ModelStatic, OLD_VALUE_NAMESPACE, OperationDefinition, OperationsDocument, Param, ParamDescriptor, type Parameterize, PartialQueryKeyOf, type PerKeyCursorEnvelope, type PlanInput, PrimaryKeyOf, type ProjectionResult, ProjectionTransform, type ProjectionValue, PutInput, QueryMethodSpec, QueryModelContract, type QueryOptions$1 as QueryOptions, QuerySpec, RawCondition, ReadExecOptions, ReadParams, ReadRequestCtx, ReadRequestKind, type RebuildResult, RelationMetadata, RelationOptions, type RelationTraversalOptions, ReplayOptions, RequestContext, ResolvedKey, RetryOverride, RetryPolicy, RetryingExecutor, SelectableOf, type SelfProxy, type SelfRef, ShardId, type SourceProxy, type SourceRef, TableMapping, TransactWriteExecItem, type TransactionDefinition, TransactionItemSpec, type TransactionParamShape, type TransactionRef, TransactionSpec, type TxConditionCheckOptions, type TxForEachInstruction, type TxForEachOptions, type TxInstruction, type TxRecorder, type TxWriteInstruction, type TxWriteOptions, UniqueQueryKeyOf, type UpdateExpressionResult, UpdateInput, type VersionedHistoryOptions, type VersionedLatestOptions, ViewDefinition, type WhenComparison, WriteDefinitionOptions, WriteExecOptions, WriteResult, aggregate, assertBundleSerializable, assertContractBoundaries, assertContractN1Safe, assertJsonSerializable, assertSupportedCondition, belongsTo, binary, boolean, buildBridgeBundle, buildConditionExpression, buildContexts, buildContracts, buildManifest, buildOperations, buildProjection, buildQuerySpec, buildTransactionSpec, buildTransactions, buildUpdateExpression, collectContractBoundaryViolations, collectContractN1Violations, compileFilterExpression, count, createCdcEmulator, createDefaultLinter, createMaintenanceDrain, createMaintenanceDrainHandler, createMaintenanceRebuilder, datetime, decodeCursor, decodePerKeyCursor, defineCommands, defineDelete, defineList, definePut, defineQueries, defineQuery, defineTransaction, defineTransactions, defineUpdate, deriveEdgeWriteItems, deriveEdgeWriteItemsFor, deriveModelEdgeWriteItems, derivePrefix, detectRelationFields, edgeWrites, embedded, encodeCursor, encodePerKeyCursor, evaluateFilter, execute, executeDeclarativeTransaction, executeExplain, executeList, executeQuery, expandTransaction, field, getEdgeWrites, getImplicitKeyFields, gsiAmbiguityRule, hasMany, hasOne, hydrate, isEdgeWritesDefinition, isSelectBuilder, isTransactionRef, list, literal, maintainedFrom, map, max, missingGsiRule, model, noScanRule, number, numberSet, plan, queryBoundaryRule, relationDepthRule, requireLimitRule, resolveKey, resolveRelations, serializeContractKey, serializeFieldValue, string, stringSet, validateDepth, validateGsiAmbiguity, when, whenMember };
|