graphddb 0.5.2 → 0.6.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 +8 -0
- package/dist/cdc/index.d.ts +37 -0
- package/dist/cdc/index.js +29 -0
- package/dist/{chunk-QBXLQNXY.js → chunk-5NXNEW43.js} +4 -1
- package/dist/{chunk-W3GEJPPV.js → chunk-F2DI3GTI.js} +154 -1024
- package/dist/chunk-MMVHOUM4.js +24 -0
- package/dist/{chunk-H5TUW2WR.js → chunk-N5NQM3SO.js} +3749 -3606
- package/dist/chunk-PDUVTYC5.js +992 -0
- package/dist/cli.js +922 -19
- package/dist/from-change-CFzBy7aU.d.ts +327 -0
- package/dist/index-CtJbTrfB.d.ts +690 -0
- package/dist/index.d.ts +53 -1113
- package/dist/index.js +48 -41
- package/dist/linter/index.d.ts +126 -0
- package/dist/linter/index.js +36 -0
- package/dist/{types-m1Ect6hG.d.ts → maintenance-view-adapter-CFeasCKo.d.ts} +380 -187
- package/dist/registry-DbqmFyab.d.ts +76 -0
- package/dist/relation-depth-0TiWr5OW.d.ts +36 -0
- package/dist/spec/index.d.ts +4 -0
- package/dist/spec/index.js +54 -0
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +5 -4
- package/docs/design-patterns.md +150 -27
- package/docs/doc-sample.md +263 -0
- package/docs/docs-generation.md +183 -0
- package/package.json +55 -4
- package/dist/chunk-MCKGQKYU.js +0 -15
- package/dist/typescript-ZUQEBJRV.js +0 -210764
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
queryBoundaryRule
|
|
3
|
+
} from "./chunk-MMVHOUM4.js";
|
|
1
4
|
import {
|
|
2
5
|
BatchGetResult,
|
|
3
6
|
DDBModel,
|
|
@@ -36,7 +39,6 @@ import {
|
|
|
36
39
|
deriveEdgeWriteItems,
|
|
37
40
|
deriveEdgeWriteItemsFor,
|
|
38
41
|
deriveModelEdgeWriteItems,
|
|
39
|
-
detectRelationFields,
|
|
40
42
|
edgeWrites,
|
|
41
43
|
encodeCursor,
|
|
42
44
|
evaluateFilter,
|
|
@@ -50,7 +52,6 @@ import {
|
|
|
50
52
|
executeQuery,
|
|
51
53
|
from,
|
|
52
54
|
getEdgeWrites,
|
|
53
|
-
getImplicitKeyFields,
|
|
54
55
|
isCommandModelContract,
|
|
55
56
|
isCommandPlan,
|
|
56
57
|
isContractComposeNode,
|
|
@@ -77,7 +78,7 @@ import {
|
|
|
77
78
|
validateDepth,
|
|
78
79
|
when,
|
|
79
80
|
wholeKeysSentinel
|
|
80
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-N5NQM3SO.js";
|
|
81
82
|
import {
|
|
82
83
|
CdcEmulator,
|
|
83
84
|
MAINT_OUTBOX_PK_PREFIX,
|
|
@@ -89,7 +90,7 @@ import {
|
|
|
89
90
|
orderAndTrimCollection,
|
|
90
91
|
pathField,
|
|
91
92
|
projectFrom
|
|
92
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-5NXNEW43.js";
|
|
93
94
|
import {
|
|
94
95
|
BATCH_GET_MAX_KEYS,
|
|
95
96
|
BATCH_WRITE_MAX_ITEMS,
|
|
@@ -99,11 +100,9 @@ import {
|
|
|
99
100
|
DynamoExecutor,
|
|
100
101
|
ENTITY_WRITES_MARKER,
|
|
101
102
|
LIFECYCLE_CONTRACT_MARKER,
|
|
102
|
-
Linter,
|
|
103
103
|
MAX_TRANSACT_ITEMS,
|
|
104
104
|
MetadataRegistry,
|
|
105
105
|
RetryingExecutor,
|
|
106
|
-
TableMapping,
|
|
107
106
|
TransactionContext,
|
|
108
107
|
attachModelClass,
|
|
109
108
|
buildConditionExpression,
|
|
@@ -118,7 +117,7 @@ import {
|
|
|
118
117
|
collectViewDefinitions,
|
|
119
118
|
commitTransaction,
|
|
120
119
|
cond,
|
|
121
|
-
|
|
120
|
+
detectRelationFields,
|
|
122
121
|
entityWrites,
|
|
123
122
|
execItemKeySignature,
|
|
124
123
|
executeDelete,
|
|
@@ -126,13 +125,11 @@ import {
|
|
|
126
125
|
executeTransaction,
|
|
127
126
|
executeUpdate,
|
|
128
127
|
getEntityWrites,
|
|
128
|
+
getImplicitKeyFields,
|
|
129
129
|
gsi,
|
|
130
|
-
gsiAmbiguityRule,
|
|
131
130
|
hydrate,
|
|
132
131
|
identity,
|
|
133
|
-
isColumn,
|
|
134
132
|
isEntityWritesDefinition,
|
|
135
|
-
isKeySegment,
|
|
136
133
|
isLifecycleContract,
|
|
137
134
|
isMaintainTrigger,
|
|
138
135
|
isParam,
|
|
@@ -140,24 +137,31 @@ import {
|
|
|
140
137
|
isRetryableError,
|
|
141
138
|
isRetryableTransactionCancellation,
|
|
142
139
|
isSelectBuilder,
|
|
143
|
-
k,
|
|
144
|
-
key,
|
|
145
140
|
lifecyclePhaseForIntent,
|
|
146
141
|
maintainTrigger,
|
|
147
|
-
missingGsiRule,
|
|
148
|
-
noScanRule,
|
|
149
142
|
param,
|
|
150
143
|
parseChange,
|
|
151
144
|
preview,
|
|
152
|
-
relationDepthRule,
|
|
153
|
-
requireLimitRule,
|
|
154
145
|
resolveConditionTree,
|
|
155
|
-
resolveKey,
|
|
156
146
|
resolveModelClass,
|
|
157
|
-
segmentFieldNames,
|
|
158
147
|
serializeFieldValue
|
|
159
|
-
} from "./chunk-
|
|
160
|
-
import
|
|
148
|
+
} from "./chunk-F2DI3GTI.js";
|
|
149
|
+
import {
|
|
150
|
+
Linter,
|
|
151
|
+
TableMapping,
|
|
152
|
+
createDefaultLinter,
|
|
153
|
+
gsiAmbiguityRule,
|
|
154
|
+
isColumn,
|
|
155
|
+
isKeySegment,
|
|
156
|
+
k,
|
|
157
|
+
key,
|
|
158
|
+
missingGsiRule,
|
|
159
|
+
noScanRule,
|
|
160
|
+
relationDepthRule,
|
|
161
|
+
requireLimitRule,
|
|
162
|
+
resolveKey,
|
|
163
|
+
segmentFieldNames
|
|
164
|
+
} from "./chunk-PDUVTYC5.js";
|
|
161
165
|
|
|
162
166
|
// src/metadata/prefix.ts
|
|
163
167
|
function derivePrefix(customPrefix, className) {
|
|
@@ -508,6 +512,29 @@ function hasMany(targetFactory, keyBindingOrCallback, options) {
|
|
|
508
512
|
});
|
|
509
513
|
};
|
|
510
514
|
}
|
|
515
|
+
function refs(targetFactory, options) {
|
|
516
|
+
return function(_value, context) {
|
|
517
|
+
const propertyName = String(context.name);
|
|
518
|
+
assertRelationPropertyNameAllowed(propertyName);
|
|
519
|
+
if (!options || typeof options.from !== "string" || typeof options.key !== "string") {
|
|
520
|
+
throw new Error(
|
|
521
|
+
`@refs relation '${propertyName}': options must supply \`from\` (the parent list attribute, e.g. 'tagRefs') and \`key\` (the ref field on each element, e.g. 'tagId').`
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
const { from: from2, key: key2, to, ...relationOptions } = options;
|
|
525
|
+
const targetKeyField = to ?? key2;
|
|
526
|
+
collectRelation({
|
|
527
|
+
type: "refs",
|
|
528
|
+
propertyName,
|
|
529
|
+
targetFactory,
|
|
530
|
+
// Scalar keyBinding: target child key field ← element key name. Per resolved
|
|
531
|
+
// element the existing scalar key-building machinery reuses this unchanged.
|
|
532
|
+
keyBinding: { [targetKeyField]: key2 },
|
|
533
|
+
refs: { from: from2, key: key2 },
|
|
534
|
+
...Object.keys(relationOptions).length > 0 ? { options: relationOptions } : {}
|
|
535
|
+
});
|
|
536
|
+
};
|
|
537
|
+
}
|
|
511
538
|
function belongsTo(targetFactory, keyBinding, options) {
|
|
512
539
|
return function(_value, context) {
|
|
513
540
|
const propertyName = String(context.name);
|
|
@@ -1250,27 +1277,6 @@ async function executeRangeFanout(op, keys, params = {}) {
|
|
|
1250
1277
|
return out;
|
|
1251
1278
|
}
|
|
1252
1279
|
|
|
1253
|
-
// src/linter/rules/query-boundary.ts
|
|
1254
|
-
var queryBoundaryRule = {
|
|
1255
|
-
id: "query-boundary",
|
|
1256
|
-
severity: "error",
|
|
1257
|
-
check(metadata) {
|
|
1258
|
-
const results = [];
|
|
1259
|
-
for (const gsi2 of metadata.gsiDefinitions) {
|
|
1260
|
-
if (!gsi2.unique) {
|
|
1261
|
-
results.push({
|
|
1262
|
-
ruleId: "query-boundary",
|
|
1263
|
-
severity: "error",
|
|
1264
|
-
message: `GSI '${gsi2.indexName}' on entity '${metadata.prefix}' is not marked as unique. Using query() on a non-unique GSI may return multiple items. Use list() instead, or mark the GSI as unique if it guarantees single results.`,
|
|
1265
|
-
entity: metadata.prefix,
|
|
1266
|
-
field: gsi2.indexName
|
|
1267
|
-
});
|
|
1268
|
-
}
|
|
1269
|
-
}
|
|
1270
|
-
return results;
|
|
1271
|
-
}
|
|
1272
|
-
};
|
|
1273
|
-
|
|
1274
1280
|
// src/relation/maintenance-rebuild.ts
|
|
1275
1281
|
function toClass(m) {
|
|
1276
1282
|
try {
|
|
@@ -2011,6 +2017,7 @@ export {
|
|
|
2011
2017
|
publicQueryModel,
|
|
2012
2018
|
query,
|
|
2013
2019
|
queryBoundaryRule,
|
|
2020
|
+
refs,
|
|
2014
2021
|
relationDepthRule,
|
|
2015
2022
|
requireLimitRule,
|
|
2016
2023
|
resolveKey,
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { L as LintRule } from '../registry-DbqmFyab.js';
|
|
2
|
+
export { a as LintResult, b as Linter } from '../registry-DbqmFyab.js';
|
|
3
|
+
export { c as createDefaultLinter, g as gsiAmbiguityRule, m as missingGsiRule, n as noScanRule, q as queryBoundaryRule, r as relationDepthRule, a as requireLimitRule } from '../relation-depth-0TiWr5OW.js';
|
|
4
|
+
import '../maintenance-view-adapter-CFeasCKo.js';
|
|
5
|
+
import '@aws-sdk/client-dynamodb';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `samePartition` preset validator (Epic #118 child issue H).
|
|
9
|
+
*
|
|
10
|
+
* The `samePartition` preset is pure **lowering sugar**: a
|
|
11
|
+
* `@hasMany(..., { pattern: 'samePartition' })` declares that the children live
|
|
12
|
+
* in the **same partition** as the parent and are reached by a `begins_with`
|
|
13
|
+
* range read on a **segmented sort key** (RFC #118: `TestCaseModel` children of
|
|
14
|
+
* `SuiteModel`, same `PROJECT#{projectId}` PK, child SK
|
|
15
|
+
* `SUITE#{suiteId}#CASE#…`). There is **no maintained materialisation** — the
|
|
16
|
+
* preset carries no new write effect; it simply names an access shape the
|
|
17
|
+
* existing segmented-key + hasMany planner already produces.
|
|
18
|
+
*
|
|
19
|
+
* Because the preset desugars onto the *exact same* metadata path as the escape
|
|
20
|
+
* hatch (a bare `@hasMany` whose `keyBinding` is a contiguous prefix of the
|
|
21
|
+
* target's primary key), this rule's role is to verify the declaration really
|
|
22
|
+
* does lower that way — so that the preset form and the escape-hatch form are
|
|
23
|
+
* guaranteed to plan identically. It rejects declarations that name the preset
|
|
24
|
+
* but cannot lower to it (wrong key shape, GSI hop, maintenance options),
|
|
25
|
+
* turning a silent mis-lowering into a build-time error.
|
|
26
|
+
*
|
|
27
|
+
* ## Integrity rules enforced
|
|
28
|
+
*
|
|
29
|
+
* 1. **hasMany only** — `samePartition` is a parent→children collection read;
|
|
30
|
+
* `belongsTo` / `hasOne` are single-target lookups and cannot lower to a
|
|
31
|
+
* same-partition `begins_with`.
|
|
32
|
+
* 2. **Same partition, SK-prefix read** — the `keyBinding` must resolve against
|
|
33
|
+
* the target's **primary key** as a `partial` match (every PK field bound,
|
|
34
|
+
* the SK a proper segment prefix → `begins_with`). A GSI hop is a *different*
|
|
35
|
+
* partition, and a `full` PK match is a point read of a single item, not a
|
|
36
|
+
* child collection: both contradict the preset.
|
|
37
|
+
* 3. **No maintenance effect** — `read` / `write` / `projection` belong to the
|
|
38
|
+
* maintained presets (`embeddedSnapshot` etc., #124/#125). `samePartition`
|
|
39
|
+
* has no maintained materialisation, so these options on it are a declaration
|
|
40
|
+
* error rather than a silently ignored field.
|
|
41
|
+
*/
|
|
42
|
+
declare const samePartitionPresetRule: LintRule;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* `missing-context` validator (Epic #118 issue #126, child G; AC: payload 非同梱
|
|
46
|
+
* 属性で error — 論点4 = payload 同梱のみ).
|
|
47
|
+
*
|
|
48
|
+
* A maintained relation (`embeddedSnapshot` etc.) projects attributes of its
|
|
49
|
+
* **source** entity (the relation target, whose lifecycle fires the maintenance)
|
|
50
|
+
* into the maintained snapshot / collection on the owner row. Phase 1 allows
|
|
51
|
+
* **payload 同梱 only** (論点4): the projection may read only attributes the
|
|
52
|
+
* source row actually carries on its write payload — there is no write-time fetch
|
|
53
|
+
* or re-projection (that is Phase 2 / stream). This rule rejects, as an `error`,
|
|
54
|
+
* any projection (or key-binding) source attribute that is absent from the source
|
|
55
|
+
* entity's payload.
|
|
56
|
+
*
|
|
57
|
+
* ## Role split vs D (#124 maintenance graph round-trip)
|
|
58
|
+
*
|
|
59
|
+
* D's `buildMaintenanceGraph` (`src/relation/maintenance-graph.ts`,
|
|
60
|
+
* `assertMaintenanceRoundTrips`) **already throws** on this exact condition when
|
|
61
|
+
* the graph is built. The overlap is deliberate and complementary, NOT redundant:
|
|
62
|
+
*
|
|
63
|
+
* - **Layer / timing.** D's reject fires only when someone *builds the graph*
|
|
64
|
+
* (compile / explicit `buildMaintenanceGraph()`); it is the build-time final
|
|
65
|
+
* defence. This rule runs inside `MetadataRegistry.finalize` (the moment a model
|
|
66
|
+
* is first resolved), so a payload-非同梱 projection is surfaced **eagerly**, as
|
|
67
|
+
* a structured per-entity `LintResult` with `entity` + `field`, alongside every
|
|
68
|
+
* other lint finding — before any graph build.
|
|
69
|
+
* - **No re-derivation.** The rule does NOT call `buildMaintenanceGraph` (that
|
|
70
|
+
* would re-derive the whole graph and, inside `finalize`, recurse through the
|
|
71
|
+
* registry). It reads the same declaration metadata (`options.projection` +
|
|
72
|
+
* `keyBinding`) and computes the same payload surface (`payloadAttributes`,
|
|
73
|
+
* mirroring D's `sourcePayloadAttributes`) directly. D remains the SSoT for the
|
|
74
|
+
* *build-time* reject; this is the user-facing linter diagnostic for the same
|
|
75
|
+
* invariant.
|
|
76
|
+
*
|
|
77
|
+
* Source-payload resolution needs the **source** (relation target) metadata, so
|
|
78
|
+
* the rule resolves it via the registry (like `relation-depth`); if the target is
|
|
79
|
+
* unregistered it is skipped here (D / other rules surface that).
|
|
80
|
+
*/
|
|
81
|
+
declare const missingContextRule: LintRule;
|
|
82
|
+
|
|
83
|
+
declare const embeddedSnapshotSizeRule: LintRule;
|
|
84
|
+
|
|
85
|
+
declare const hotPartitionRule: LintRule;
|
|
86
|
+
|
|
87
|
+
declare const fanOutRule: LintRule;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* `multi-maintainer-same-row` validator (Epic #118 issue #126, child G; AC: 同一
|
|
91
|
+
* 行への複数 maintain 効果で error — 論点2 = (b)).
|
|
92
|
+
*
|
|
93
|
+
* 論点2 was decided **(b)**: Phase 1 constrains maintenance to "**1 mutation × 1
|
|
94
|
+
* target row = 1 maintain effect**". If two or more maintained relations would,
|
|
95
|
+
* under the **same** trigger, write the **same** destination (owner) row, a single
|
|
96
|
+
* mutation would touch that one row twice — the same one-row-twice collision
|
|
97
|
+
* DynamoDB rejects in a `TransactWriteItems`, and the case #96 made a loud reject.
|
|
98
|
+
* This rule flags that configuration as an **error**.
|
|
99
|
+
*
|
|
100
|
+
* ## Consuming D's `multiMaintainerTargets` (#124) — and why this rule recomputes
|
|
101
|
+
* the same grouping locally
|
|
102
|
+
*
|
|
103
|
+
* D's `buildMaintenanceGraph` exposes exactly this collision material as
|
|
104
|
+
* `MaintenanceGraph.multiMaintainerTargets` (grouped by `"<trigger>
|
|
105
|
+
* <destinationRowKey>"`, only groups of size > 1). By design D **surfaces** the
|
|
106
|
+
* collision without rejecting (its header: "#124 surfaces it, #125/#126 decide the
|
|
107
|
+
* reject") — and `destinationRowKey` is built as
|
|
108
|
+
* `"<ownerEntity>#<sorted ownerField=$.entity.sourceField>"`, so a collision is
|
|
109
|
+
* **always among one owner entity's own relations** (the owner name is part of the
|
|
110
|
+
* key, so two different entities can never share a destination row — confirmed by
|
|
111
|
+
* D's test "different owner entities → no collision").
|
|
112
|
+
*
|
|
113
|
+
* That fact is what lets this linter rule run **per-entity** inside
|
|
114
|
+
* `MetadataRegistry.finalize`: it recomputes D's `(trigger, destinationRowKey)`
|
|
115
|
+
* grouping over **this entity's own** maintained relations — the identical
|
|
116
|
+
* collision predicate, restricted to the only scope a collision can occur in — so
|
|
117
|
+
* it never needs to build the global graph (which, inside `finalize`, would
|
|
118
|
+
* re-enter the registry). The role split mirrors `missing-context`: D is the
|
|
119
|
+
* build-time material / final-defence, G is the eager user-facing linter
|
|
120
|
+
* diagnostic. The complementary compile-time reject is E (#125, NOT touched here).
|
|
121
|
+
*/
|
|
122
|
+
declare const multiMaintainerSameRowRule: LintRule;
|
|
123
|
+
|
|
124
|
+
declare const cfnSchemaConsistencyRule: LintRule;
|
|
125
|
+
|
|
126
|
+
export { LintRule, cfnSchemaConsistencyRule, embeddedSnapshotSizeRule, fanOutRule, hotPartitionRule, missingContextRule, multiMaintainerSameRowRule, samePartitionPresetRule };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
queryBoundaryRule
|
|
3
|
+
} from "../chunk-MMVHOUM4.js";
|
|
4
|
+
import {
|
|
5
|
+
Linter,
|
|
6
|
+
cfnSchemaConsistencyRule,
|
|
7
|
+
createDefaultLinter,
|
|
8
|
+
embeddedSnapshotSizeRule,
|
|
9
|
+
fanOutRule,
|
|
10
|
+
gsiAmbiguityRule,
|
|
11
|
+
hotPartitionRule,
|
|
12
|
+
missingContextRule,
|
|
13
|
+
missingGsiRule,
|
|
14
|
+
multiMaintainerSameRowRule,
|
|
15
|
+
noScanRule,
|
|
16
|
+
relationDepthRule,
|
|
17
|
+
requireLimitRule,
|
|
18
|
+
samePartitionPresetRule
|
|
19
|
+
} from "../chunk-PDUVTYC5.js";
|
|
20
|
+
export {
|
|
21
|
+
Linter,
|
|
22
|
+
cfnSchemaConsistencyRule,
|
|
23
|
+
createDefaultLinter,
|
|
24
|
+
embeddedSnapshotSizeRule,
|
|
25
|
+
fanOutRule,
|
|
26
|
+
gsiAmbiguityRule,
|
|
27
|
+
hotPartitionRule,
|
|
28
|
+
missingContextRule,
|
|
29
|
+
missingGsiRule,
|
|
30
|
+
multiMaintainerSameRowRule,
|
|
31
|
+
noScanRule,
|
|
32
|
+
queryBoundaryRule,
|
|
33
|
+
relationDepthRule,
|
|
34
|
+
requireLimitRule,
|
|
35
|
+
samePartitionPresetRule
|
|
36
|
+
};
|