graphddb 0.5.3 → 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.
@@ -1,5 +1,5 @@
1
- export { C as CdcEmulator, M as MAINT_OUTBOX_PK_PREFIX, a as MaintenanceDrain, b as MaintenanceDrainOptions, c as createCdcEmulator, d as createMaintenanceDrain, e as createMaintenanceDrainHandler, p as parseChange } from '../from-change-DQK2Jm9R.js';
2
- export { B as BatchResult, C as CdcEmulatorOptions, a as CdcMode, b as ChangeBatch, c as ChangeEvent, d as ChangeEventName, e as ChangeHandler, f as ClockMode, g as ConcurrentRecomputeRef, E as EventLog, F as FaultSpec, R as ReplayOptions, S as ShardId, h as StartingPosition, i as StreamViewType, j as SubscribeHandler, k as SubscribeHandlers, U as Unsubscribe, l as buildSubscribeHandler } from '../maintenance-view-adapter-D5t9taTE.js';
1
+ export { C as CdcEmulator, M as MAINT_OUTBOX_PK_PREFIX, a as MaintenanceDrain, b as MaintenanceDrainOptions, c as createCdcEmulator, d as createMaintenanceDrain, e as createMaintenanceDrainHandler, p as parseChange } from '../from-change-CFzBy7aU.js';
2
+ export { B as BatchResult, C as CdcEmulatorOptions, a as CdcMode, b as ChangeBatch, c as ChangeEvent, d as ChangeEventName, e as ChangeHandler, f as ClockMode, g as ConcurrentRecomputeRef, E as EventLog, F as FaultSpec, R as ReplayOptions, S as ShardId, h as StartingPosition, i as StreamViewType, j as SubscribeHandler, k as SubscribeHandlers, U as Unsubscribe, l as buildSubscribeHandler } from '../maintenance-view-adapter-CFeasCKo.js';
3
3
  import '@aws-sdk/client-dynamodb';
4
4
 
5
5
  /**
package/dist/cdc/index.js CHANGED
@@ -8,11 +8,11 @@ import {
8
8
  createMaintenanceDrainHandler,
9
9
  hashString,
10
10
  shardIdFor
11
- } from "../chunk-M6URQOAW.js";
11
+ } from "../chunk-5NXNEW43.js";
12
12
  import {
13
13
  buildSubscribeHandler,
14
14
  parseChange
15
- } from "../chunk-CCIVET5K.js";
15
+ } from "../chunk-F2DI3GTI.js";
16
16
  import "../chunk-PDUVTYC5.js";
17
17
  export {
18
18
  CdcEmulator,
@@ -7,7 +7,7 @@ import {
7
7
  buildMaintenanceGraph,
8
8
  buildPutInput,
9
9
  resolveModelClass
10
- } from "./chunk-CCIVET5K.js";
10
+ } from "./chunk-F2DI3GTI.js";
11
11
 
12
12
  // src/cdc/prng.ts
13
13
  var SeededRandom = class {
@@ -245,6 +245,73 @@ function buildRelation(select) {
245
245
  });
246
246
  }
247
247
 
248
+ // src/relation/detect.ts
249
+ function isRelationSpec(value) {
250
+ if (typeof value !== "object" || value === null) return false;
251
+ return "select" in value || isSelectBuilder(value);
252
+ }
253
+ function isInlineSnapshotSpec(value) {
254
+ return typeof value === "object" && value !== null && !isSelectBuilder(value) && value.inline === true && !("select" in value);
255
+ }
256
+ function detectRelationFields(select, metadata) {
257
+ const result = [];
258
+ for (const [fieldName, value] of Object.entries(select)) {
259
+ if (isRelationSpec(value)) {
260
+ const rel = metadata.relations.find((r) => r.propertyName === fieldName);
261
+ if (rel) {
262
+ result.push(rel);
263
+ }
264
+ }
265
+ }
266
+ return result;
267
+ }
268
+ function validateInlineSnapshotSelect(select, metadata, resolveTargetMeta) {
269
+ for (const [fieldName, value] of Object.entries(select)) {
270
+ if (isInlineSnapshotSpec(value)) {
271
+ const rel = metadata.relations.find((r) => r.propertyName === fieldName);
272
+ if (!rel) {
273
+ throw new Error(
274
+ `Inline read '{ ${fieldName}: { inline: true } }' is only valid on an embeddedSnapshot relation, but '${fieldName}' is not a relation on '${metadata.prefix}'. Use '${fieldName}: true' for a scalar / embedded field.`
275
+ );
276
+ }
277
+ if (rel.options?.pattern !== "embeddedSnapshot") {
278
+ throw new Error(
279
+ `Inline read '{ ${fieldName}: { inline: true } }' is only valid on an embeddedSnapshot relation. '${fieldName}' is a plain '${rel.type}' relation (no 'pattern: embeddedSnapshot'); use '{ ${fieldName}: { select: \u2026 } }' to traverse to its child rows instead.`
280
+ );
281
+ }
282
+ continue;
283
+ }
284
+ if (typeof value === "object" && value !== null && isRelationSpec(value)) {
285
+ const rel = metadata.relations.find((r) => r.propertyName === fieldName);
286
+ if (!rel) continue;
287
+ const targetMeta = resolveTargetMeta(rel);
288
+ const nested = normalizeSelectSpec(value).select;
289
+ if (nested) {
290
+ validateInlineSnapshotSelect(nested, targetMeta, resolveTargetMeta);
291
+ }
292
+ }
293
+ }
294
+ }
295
+ function getImplicitKeyFields(select, metadata) {
296
+ const relations = detectRelationFields(select, metadata);
297
+ const needed = /* @__PURE__ */ new Set();
298
+ for (const rel of relations) {
299
+ if (rel.type === "refs" && rel.refs) {
300
+ const listField = rel.refs.from;
301
+ if (!(listField in select) || select[listField] !== true) {
302
+ needed.add(listField);
303
+ }
304
+ continue;
305
+ }
306
+ for (const sourceField of Object.values(rel.keyBinding)) {
307
+ if (!(sourceField in select) || select[sourceField] !== true) {
308
+ needed.add(sourceField);
309
+ }
310
+ }
311
+ }
312
+ return [...needed];
313
+ }
314
+
248
315
  // src/define/param.ts
249
316
  function isParamOptions(value) {
250
317
  return typeof value === "object" && value !== null;
@@ -2718,6 +2785,11 @@ function hydrateItem(raw, select, metadata, updatable = false) {
2718
2785
  const fieldMeta = fieldMap.get(fieldName);
2719
2786
  result[fieldName] = deserializeValue(value, fieldMeta);
2720
2787
  }
2788
+ } else if (isInlineSnapshotSpec(selectValue)) {
2789
+ const value = raw[fieldName];
2790
+ if (value !== void 0) {
2791
+ result[fieldName] = value;
2792
+ }
2721
2793
  } else if (typeof selectValue === "object" && selectValue !== null) {
2722
2794
  if ("select" in selectValue || isSelectBuilder(selectValue)) {
2723
2795
  continue;
@@ -2856,6 +2928,18 @@ var recorder = {
2856
2928
  deleteEdge(targetFactory, relationProperty) {
2857
2929
  return { kind: "deleteEdge", targetFactory, relationProperty };
2858
2930
  },
2931
+ dualEdge(forward, inverse) {
2932
+ return {
2933
+ kind: "putEdge",
2934
+ targetFactory: forward.target,
2935
+ relationProperty: forward.relationProperty,
2936
+ inverse: {
2937
+ adjacencyFactory: inverse.adjacency,
2938
+ targetFactory: inverse.target,
2939
+ relationProperty: inverse.relationProperty
2940
+ }
2941
+ };
2942
+ },
2859
2943
  increment(targetFactory, keys, attribute, amount) {
2860
2944
  return { kind: "derive", targetFactory, keys, attribute, amount };
2861
2945
  },
@@ -3713,6 +3797,10 @@ export {
3713
3797
  normalizeTopLevelSelect,
3714
3798
  buildProject,
3715
3799
  buildRelation,
3800
+ isInlineSnapshotSpec,
3801
+ detectRelationFields,
3802
+ validateInlineSnapshotSelect,
3803
+ getImplicitKeyFields,
3716
3804
  param,
3717
3805
  isParam,
3718
3806
  BATCH_GET_MAX_KEYS,
@@ -22,14 +22,17 @@ import {
22
22
  commitTransaction,
23
23
  compileRawCondition,
24
24
  ctxModelFor,
25
+ detectRelationFields,
25
26
  execItemKeySignature,
26
27
  executeDelete,
27
28
  executePut,
28
29
  executeTransaction,
29
30
  executeUpdate,
30
31
  getEntityWrites,
32
+ getImplicitKeyFields,
31
33
  hydrate,
32
34
  isEntityWritesDefinition,
35
+ isInlineSnapshotSpec,
33
36
  isLifecycleContract,
34
37
  isParam,
35
38
  isRawCondition,
@@ -44,8 +47,9 @@ import {
44
47
  resolveSegmentedKey,
45
48
  serializeFieldValue,
46
49
  serializeRawCondition,
47
- skTemplate
48
- } from "./chunk-CCIVET5K.js";
50
+ skTemplate,
51
+ validateInlineSnapshotSelect
52
+ } from "./chunk-F2DI3GTI.js";
49
53
  import {
50
54
  TableMapping,
51
55
  createColumnMap,
@@ -116,6 +120,10 @@ function buildRelations(metadata) {
116
120
  type: rel.type,
117
121
  target: targetClass.name,
118
122
  keyBinding: { ...rel.keyBinding },
123
+ // List-valued source descriptor for a `refs` relation (issue #197); emitted
124
+ // only for `refs` so a scalar-keyed relation is byte-identical to the pre-#197
125
+ // manifest.
126
+ ...rel.refs !== void 0 ? { refs: { ...rel.refs } } : {},
119
127
  // Purely-documentary relation description (issue #166); emitted only when
120
128
  // declared so an undescribed relation is byte-identical to the pre-#166 manifest.
121
129
  ...rel.options?.description !== void 0 ? { description: rel.options.description } : {}
@@ -190,36 +198,6 @@ function buildManifest(registry = MetadataRegistry) {
190
198
  };
191
199
  }
192
200
 
193
- // src/relation/detect.ts
194
- function isRelationSpec(value) {
195
- if (typeof value !== "object" || value === null) return false;
196
- return "select" in value || isSelectBuilder(value);
197
- }
198
- function detectRelationFields(select, metadata) {
199
- const result = [];
200
- for (const [fieldName, value] of Object.entries(select)) {
201
- if (isRelationSpec(value)) {
202
- const rel = metadata.relations.find((r) => r.propertyName === fieldName);
203
- if (rel) {
204
- result.push(rel);
205
- }
206
- }
207
- }
208
- return result;
209
- }
210
- function getImplicitKeyFields(select, metadata) {
211
- const relations = detectRelationFields(select, metadata);
212
- const needed = /* @__PURE__ */ new Set();
213
- for (const rel of relations) {
214
- for (const sourceField of Object.values(rel.keyBinding)) {
215
- if (!(sourceField in select) || select[sourceField] !== true) {
216
- needed.add(sourceField);
217
- }
218
- }
219
- }
220
- return [...needed];
221
- }
222
-
223
201
  // src/planner/projection.ts
224
202
  function buildProjection(select, additionalFields) {
225
203
  const paths = [];
@@ -237,6 +215,8 @@ function buildProjection(select, additionalFields) {
237
215
  for (const [fieldName, value] of Object.entries(selectObj)) {
238
216
  if (value === true) {
239
217
  addPath([...parentSegments, fieldName]);
218
+ } else if (isInlineSnapshotSpec(value)) {
219
+ addPath([...parentSegments, fieldName]);
240
220
  } else if (typeof value === "object" && value !== null) {
241
221
  if ("select" in value || isSelectBuilder(value)) {
242
222
  continue;
@@ -702,6 +682,11 @@ async function executeListInternal(modelClass, key, selectSpec, options = {}) {
702
682
  const after = options.after ?? normalized.after;
703
683
  const limit = options.limit ?? normalized.limit;
704
684
  const order = options.order ?? normalized.order;
685
+ validateInlineSnapshotSelect(
686
+ select,
687
+ metadata,
688
+ (rel) => MetadataRegistry.get(rel.targetFactory())
689
+ );
705
690
  const exclusiveStartKey = after ? decodeCursor(after) : void 0;
706
691
  const implicitKeys = getImplicitKeyFields(select, metadata);
707
692
  const executionPlan = plan(metadata, {
@@ -970,7 +955,7 @@ function relationResultPaths(select, metadata, parentPath = "$") {
970
955
  const childSelect = normalizeSelectSpec(select[rel.propertyName]).select ?? {};
971
956
  const targetMeta = MetadataRegistry.get(rel.targetFactory());
972
957
  const childPath = `${parentPath}.${rel.propertyName}`;
973
- const isMany = rel.type === "hasMany";
958
+ const isMany = rel.type === "hasMany" || rel.type === "refs";
974
959
  const resultPath = isMany ? `${childPath}.items` : childPath;
975
960
  out.push({
976
961
  propertyName: rel.propertyName,
@@ -1064,7 +1049,7 @@ function validateDepth(select, metadata, maxDepth, currentDepth = 1) {
1064
1049
  }
1065
1050
  function relationResultPath(parentPath, rel) {
1066
1051
  const base = `${parentPath}.${rel.propertyName}`;
1067
- return rel.type === "hasMany" ? `${base}.items` : base;
1052
+ return rel.type === "hasMany" || rel.type === "refs" ? `${base}.items` : base;
1068
1053
  }
1069
1054
  function stageRelations(relations, parentPath, plan2) {
1070
1055
  if (plan2 === void 0 || relations.length === 0) {
@@ -1188,6 +1173,95 @@ async function fetchBelongsToHasOneBatch(rel, rawParentItems, selectSpec, target
1188
1173
  );
1189
1174
  return results;
1190
1175
  }
1176
+ async function fetchRefsList(rel, rawParentItem, selectSpec, targetMeta, options, currentDepth, ownPath) {
1177
+ const refsBinding = rel.refs;
1178
+ if (!refsBinding) {
1179
+ throw new Error(
1180
+ `Relation '${rel.propertyName}' is type 'refs' but carries no refs binding.`
1181
+ );
1182
+ }
1183
+ const [targetKeyField] = Object.keys(rel.keyBinding);
1184
+ const rawList = rawParentItem[refsBinding.from];
1185
+ const elements = Array.isArray(rawList) ? rawList : [];
1186
+ const queryKeys = [];
1187
+ for (const element of elements) {
1188
+ const refValue = element != null && typeof element === "object" ? element[refsBinding.key] : element;
1189
+ if (refValue == null) continue;
1190
+ queryKeys.push({ [targetKeyField]: refValue });
1191
+ }
1192
+ if (queryKeys.length === 0) {
1193
+ return [];
1194
+ }
1195
+ const implicitKeys = getImplicitKeyFields(selectSpec.select, targetMeta);
1196
+ const projectionExtras = options.updatable ? [...implicitKeys, "PK", "SK"] : implicitKeys;
1197
+ const batchOps = planBatchGetForQueryKeys(
1198
+ targetMeta,
1199
+ queryKeys,
1200
+ selectSpec.select,
1201
+ projectionExtras.length > 0 ? projectionExtras : void 0
1202
+ );
1203
+ const executor = ClientManager.getExecutor();
1204
+ const queryKeyToRaw = /* @__PURE__ */ new Map();
1205
+ const mw = options.mw ?? NO_MIDDLEWARE;
1206
+ const opPath = [...options.relationPath ?? [], rel.propertyName];
1207
+ const opModel = mw.active ? ctxModelFor(rel.targetFactory()) : void 0;
1208
+ for (const operation of batchOps) {
1209
+ const items = mw.active ? await mw.runOp(
1210
+ operation,
1211
+ opPath,
1212
+ opModel,
1213
+ (op) => executor.batchGet(
1214
+ op,
1215
+ options.retry !== void 0 ? { retry: options.retry } : void 0
1216
+ ).then((r) => r.items)
1217
+ ) : (await executor.batchGet(
1218
+ operation,
1219
+ options.retry !== void 0 ? { retry: options.retry } : void 0
1220
+ )).items;
1221
+ for (const item of items) {
1222
+ for (const queryKey of queryKeys) {
1223
+ if (!matchesQueryKey(item, queryKey)) continue;
1224
+ queryKeyToRaw.set(serializeQueryKey(queryKey), item);
1225
+ }
1226
+ }
1227
+ }
1228
+ const nestedRelations = detectRelationFields(selectSpec.select, targetMeta);
1229
+ const seen = /* @__PURE__ */ new Set();
1230
+ const orderedKeys = [];
1231
+ for (const queryKey of queryKeys) {
1232
+ const serialized = serializeQueryKey(queryKey);
1233
+ if (seen.has(serialized)) continue;
1234
+ seen.add(serialized);
1235
+ orderedKeys.push(queryKey);
1236
+ }
1237
+ const resolved = orderedKeys.map(() => null);
1238
+ await mapWithConcurrency(
1239
+ orderedKeys,
1240
+ options.plan?.plan.concurrency ?? RELATION_TRAVERSAL_CONCURRENCY,
1241
+ async (queryKey, index) => {
1242
+ const raw = queryKeyToRaw.get(serializeQueryKey(queryKey));
1243
+ if (!raw) return;
1244
+ const updatable = options.updatable ?? false;
1245
+ let item = hydrate([raw], selectSpec.select, targetMeta, updatable)[0] ?? null;
1246
+ if (item && nestedRelations.length > 0) {
1247
+ item = await resolveRelations(
1248
+ item,
1249
+ raw,
1250
+ selectSpec.select,
1251
+ targetMeta,
1252
+ options,
1253
+ currentDepth + 1,
1254
+ ownPath
1255
+ );
1256
+ if (item && updatable) attachHiddenKey(item, raw);
1257
+ }
1258
+ if (item && passesPostLoad(item, selectSpec, targetMeta)) {
1259
+ resolved[index] = item;
1260
+ }
1261
+ }
1262
+ );
1263
+ return resolved.filter((item) => item !== null);
1264
+ }
1191
1265
  function passesPostLoad(item, spec, targetMeta) {
1192
1266
  if (spec.filter && !evaluateFilterClientSide(item, spec.filter, targetMeta)) {
1193
1267
  return false;
@@ -1270,6 +1344,21 @@ async function resolveRelations(parentItem, rawParentItem, select, metadata, opt
1270
1344
  };
1271
1345
  return;
1272
1346
  }
1347
+ if (rel.type === "refs") {
1348
+ const targetClass2 = rel.targetFactory();
1349
+ const targetMeta2 = MetadataRegistry.get(targetClass2);
1350
+ const items = await fetchRefsList(
1351
+ rel,
1352
+ rawParentItem,
1353
+ selectSpec,
1354
+ targetMeta2,
1355
+ opts,
1356
+ currentDepth,
1357
+ ownPath
1358
+ );
1359
+ result[rel.propertyName] = { items, cursor: null };
1360
+ return;
1361
+ }
1273
1362
  const targetClass = rel.targetFactory();
1274
1363
  const targetMeta = MetadataRegistry.get(targetClass);
1275
1364
  const [resolvedItem] = await fetchBelongsToHasOneBatch(
@@ -1329,6 +1418,11 @@ async function executeQueryInner(modelClass, key, selectSpec, options, mw) {
1329
1418
  const normalized = normalizeTopLevelSelect(selectSpec);
1330
1419
  const select = normalized.select;
1331
1420
  const filter = normalized.filter;
1421
+ validateInlineSnapshotSelect(
1422
+ select,
1423
+ metadata,
1424
+ (rel) => MetadataRegistry.get(rel.targetFactory())
1425
+ );
1332
1426
  const maxDepth = options?.maxDepth ?? 1;
1333
1427
  const relations = detectRelationFields(select, metadata);
1334
1428
  if (relations.length > 0) {
@@ -1346,8 +1440,13 @@ async function executeQueryInner(modelClass, key, selectSpec, options, mw) {
1346
1440
  });
1347
1441
  const operation = executionPlan.operations[0];
1348
1442
  const canParallelizeRelations = relations.length > 0 && relations.every(
1349
- (rel) => Object.values(rel.keyBinding).every(
1350
- (sourceField) => key[sourceField] != null
1443
+ (rel) => (
1444
+ // A `refs` relation (issue #197) resolves from the parent row's inline
1445
+ // id-list (`refs.from`), which only exists on the FETCHED parent — never the
1446
+ // input key — so it can never be dispatched before the parent read.
1447
+ rel.type !== "refs" && Object.values(rel.keyBinding).every(
1448
+ (sourceField) => key[sourceField] != null
1449
+ )
1351
1450
  )
1352
1451
  );
1353
1452
  const retry = options?.retry;
@@ -1887,7 +1986,7 @@ function deriveOneConditionCheck(fragment, req) {
1887
1986
  return { entity: { name: targetName, modelClass: targetClass }, keyBinding };
1888
1987
  }
1889
1988
  function deriveEdgeWrites(fragment, edges, lifecycle) {
1890
- return edges.map((edge) => deriveOneEdgeWrite(fragment, edge, lifecycle));
1989
+ return edges.flatMap((edge) => deriveOneEdgeWrite(fragment, edge, lifecycle));
1891
1990
  }
1892
1991
  function deriveOneEdgeWrite(fragment, edge, lifecycle) {
1893
1992
  const targetClass = edge.targetFactory();
@@ -1903,16 +2002,48 @@ function deriveOneEdgeWrite(fragment, edge, lifecycle) {
1903
2002
  );
1904
2003
  }
1905
2004
  const adjacencyClass = relation.targetFactory();
1906
- const items = deriveEdgeWriteItemsFor(
2005
+ if (edge.inverse === void 0) {
2006
+ const items = deriveEdgeWriteItemsFor(
2007
+ adjacencyClass,
2008
+ { targetFactory: edge.targetFactory, relationProperty: edge.relationProperty },
2009
+ lifecycle
2010
+ );
2011
+ return [
2012
+ {
2013
+ entity: { name: adjacencyClass.name, modelClass: adjacencyClass },
2014
+ relation: { target: targetClass.name, property: edge.relationProperty },
2015
+ items
2016
+ }
2017
+ ];
2018
+ }
2019
+ const inverseAdjacency = edge.inverse.adjacencyFactory();
2020
+ const allItems = deriveEdgeWriteItemsFor(
1907
2021
  adjacencyClass,
1908
- { targetFactory: edge.targetFactory, relationProperty: edge.relationProperty },
2022
+ {
2023
+ targetFactory: edge.targetFactory,
2024
+ relationProperty: edge.relationProperty,
2025
+ inverse: edge.inverse
2026
+ },
1909
2027
  lifecycle
1910
2028
  );
1911
- return {
1912
- entity: { name: adjacencyClass.name, modelClass: adjacencyClass },
1913
- relation: { target: targetClass.name, property: edge.relationProperty },
1914
- items
1915
- };
2029
+ const forwardItems = allItems.filter((it) => it.entity === adjacencyClass.name);
2030
+ const inverseItems = allItems.filter((it) => it.entity === inverseAdjacency.name);
2031
+ const inverseTargetClass = edge.inverse.targetFactory();
2032
+ return [
2033
+ {
2034
+ entity: { name: adjacencyClass.name, modelClass: adjacencyClass },
2035
+ relation: { target: targetClass.name, property: edge.relationProperty },
2036
+ items: forwardItems
2037
+ },
2038
+ {
2039
+ entity: { name: inverseAdjacency.name, modelClass: inverseAdjacency },
2040
+ relation: {
2041
+ target: inverseTargetClass.name,
2042
+ property: edge.inverse.relationProperty
2043
+ },
2044
+ items: inverseItems
2045
+ }
2046
+ ];
1916
2047
  }
1917
2048
  function deriveUpdates(fragment, derive) {
1918
2049
  return derive.map((d) => deriveOneUpdate(fragment, d));
@@ -6669,6 +6800,11 @@ function buildRelationOperations(metadata, select, parentPath) {
6669
6800
  const targetClass = rel.targetFactory();
6670
6801
  const targetMeta = MetadataRegistry.get(targetClass);
6671
6802
  const childPath = `${parentPath}.${rel.propertyName}`;
6803
+ if (rel.type === "refs") {
6804
+ throw new Error(
6805
+ `Relation '${rel.propertyName}' is a 'refs' relation (issue #197): its read fans an inline parent-row id-list ('${rel.refs?.from}[].${rel.refs?.key}') out into one BatchGet. The static operations spec / Python codegen cannot represent a parent-list key fan-out (operation key conditions bind a single scalar '{result.*}'), so a 'refs' relation is resolvable ONLY through the TS in-process runtime (Model.query). Remove '${rel.propertyName}' from selects that are compiled to operations.json / generated Python, or resolve it with a separate BatchGet in the generated-code consumer.`
6806
+ );
6807
+ }
6672
6808
  if (rel.type === "hasMany") {
6673
6809
  const limit = spec.limit ?? rel.options?.limit?.default ?? 20;
6674
6810
  ops.push(
@@ -6946,8 +7082,6 @@ export {
6946
7082
  SPEC_VERSION,
6947
7083
  MARKER_ROW_ENTITY,
6948
7084
  buildManifest,
6949
- detectRelationFields,
6950
- getImplicitKeyFields,
6951
7085
  buildProjection,
6952
7086
  compileFilterExpression,
6953
7087
  evaluateFilter,
package/dist/cli.js CHANGED
@@ -3,11 +3,11 @@ import {
3
3
  buildBridgeBundle,
4
4
  buildManifest,
5
5
  buildOperations
6
- } from "./chunk-Y7XV5QL2.js";
6
+ } from "./chunk-N5NQM3SO.js";
7
7
  import {
8
8
  MetadataRegistry,
9
9
  normalizeSelectSpec
10
- } from "./chunk-CCIVET5K.js";
10
+ } from "./chunk-F2DI3GTI.js";
11
11
  import {
12
12
  createDefaultLinter
13
13
  } from "./chunk-PDUVTYC5.js";
@@ -744,6 +744,11 @@ function collectResultTypes(manifest, entity, select, typeName, out, seen) {
744
744
  const value = select[field];
745
745
  const relation = meta?.relations[field];
746
746
  if (relation) {
747
+ if (relation.type === "refs") {
748
+ throw new Error(
749
+ `Relation '${field}' on '${relation.target}' is a 'refs' relation (issue #197): it is resolvable only through the TS in-process runtime, not the Python runtime (its parent-list BatchGet fan-out has no static-spec / Python representation). Remove '${field}' from selects compiled to generated Python types.`
750
+ );
751
+ }
747
752
  const spec = normalizeSelectSpec(value);
748
753
  const childSelect = spec.select ?? {};
749
754
  const itemTypeName = `${typeName}${toPascalCase(field)}Item`;
@@ -1,4 +1,4 @@
1
- import { C as CdcEmulatorOptions, e as ChangeHandler, U as Unsubscribe, F as FaultSpec, g as ConcurrentRecomputeRef, c as ChangeEvent, E as EventLog, R as ReplayOptions, S as ShardId, V as ViewDefinition, m as EntityMetadata } from './maintenance-view-adapter-D5t9taTE.js';
1
+ import { C as CdcEmulatorOptions, e as ChangeHandler, U as Unsubscribe, F as FaultSpec, g as ConcurrentRecomputeRef, c as ChangeEvent, E as EventLog, R as ReplayOptions, S as ShardId, V as ViewDefinition, m as EntityMetadata } from './maintenance-view-adapter-CFeasCKo.js';
2
2
 
3
3
  /**
4
4
  * CDC emulator (issue #72). Subscribes to the core write-capture seam
@@ -1,5 +1,5 @@
1
- import { x as ParamDescriptor, y as EntityRef, z as ConditionInput, A as Param, M as ModelStatic, w as DDBModel, Q as QueryModelContract, G as QueryMethodSpec, H as CommandModelContract, I as CommandMethodSpec, J as ContractSpec, K as QuerySpec, L as CommandSpec, N as TransactionSpec, O as ContextSpec, X as DefinitionMap, Y as OperationsDocument, Z as AnyOperationDefinition, _ as Manifest, $ as BridgeBundle, a0 as ConditionSpec } from './maintenance-view-adapter-D5t9taTE.js';
2
- import { M as MetadataRegistry } from './registry-BD_5Rm5C.js';
1
+ import { x as ParamDescriptor, y as EntityRef, z as ConditionInput, A as Param, M as ModelStatic, w as DDBModel, Q as QueryModelContract, G as QueryMethodSpec, H as CommandModelContract, I as CommandMethodSpec, J as ContractSpec, K as QuerySpec, L as CommandSpec, N as TransactionSpec, O as ContextSpec, X as DefinitionMap, Y as OperationsDocument, Z as AnyOperationDefinition, _ as Manifest, $ as BridgeBundle, a0 as ConditionSpec } from './maintenance-view-adapter-CFeasCKo.js';
2
+ import { M as MetadataRegistry } from './registry-DbqmFyab.js';
3
3
 
4
4
  /**
5
5
  * Declarative transaction definition DSL (issue #46, Python-bridge Phase 4).