graphddb 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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,
@@ -77,7 +80,7 @@ import {
77
80
  validateDepth,
78
81
  when,
79
82
  wholeKeysSentinel
80
- } from "./chunk-H5TUW2WR.js";
83
+ } from "./chunk-Y7XV5QL2.js";
81
84
  import {
82
85
  CdcEmulator,
83
86
  MAINT_OUTBOX_PK_PREFIX,
@@ -89,7 +92,7 @@ import {
89
92
  orderAndTrimCollection,
90
93
  pathField,
91
94
  projectFrom
92
- } from "./chunk-QBXLQNXY.js";
95
+ } from "./chunk-M6URQOAW.js";
93
96
  import {
94
97
  BATCH_GET_MAX_KEYS,
95
98
  BATCH_WRITE_MAX_ITEMS,
@@ -99,11 +102,9 @@ import {
99
102
  DynamoExecutor,
100
103
  ENTITY_WRITES_MARKER,
101
104
  LIFECYCLE_CONTRACT_MARKER,
102
- Linter,
103
105
  MAX_TRANSACT_ITEMS,
104
106
  MetadataRegistry,
105
107
  RetryingExecutor,
106
- TableMapping,
107
108
  TransactionContext,
108
109
  attachModelClass,
109
110
  buildConditionExpression,
@@ -118,7 +119,6 @@ import {
118
119
  collectViewDefinitions,
119
120
  commitTransaction,
120
121
  cond,
121
- createDefaultLinter,
122
122
  entityWrites,
123
123
  execItemKeySignature,
124
124
  executeDelete,
@@ -127,12 +127,9 @@ import {
127
127
  executeUpdate,
128
128
  getEntityWrites,
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-W3GEJPPV.js";
160
- import "./chunk-MCKGQKYU.js";
148
+ } from "./chunk-CCIVET5K.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) {
@@ -1250,27 +1254,6 @@ async function executeRangeFanout(op, keys, params = {}) {
1250
1254
  return out;
1251
1255
  }
1252
1256
 
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
1257
  // src/relation/maintenance-rebuild.ts
1275
1258
  function toClass(m) {
1276
1259
  try {
@@ -0,0 +1,126 @@
1
+ import { L as LintRule } from '../registry-BD_5Rm5C.js';
2
+ export { a as LintResult, b as Linter } from '../registry-BD_5Rm5C.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-DLkhG0xX.js';
4
+ import '../maintenance-view-adapter-D5t9taTE.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
+ };