graphddb 0.1.1 → 0.2.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 CHANGED
@@ -217,11 +217,8 @@ The return type is inferred from `select`:
217
217
  ```ts
218
218
  const result = await GroupMembership.list(
219
219
  { groupId: 'eng' },
220
- {
221
- select: { userId: true, role: true },
222
- limit: 20,
223
- after: cursor,
224
- },
220
+ { userId: true, role: true },
221
+ { limit: 20, after: cursor },
225
222
  );
226
223
  // result.items: GroupMembership[]
227
224
  // result.cursor: string | null
@@ -238,8 +235,8 @@ logical groups. It is typed against the **full entity**, so it can reference att
238
235
  ```ts
239
236
  const result = await Order.list(
240
237
  { userId: 'u001' },
238
+ { orderId: true }, // amount / status need not be projected
241
239
  {
242
- select: { orderId: true }, // amount / status need not be projected
243
240
  filter: {
244
241
  status: 'confirmed', // #status = :v (equality shorthand)
245
242
  amount: { gt: 100 }, // #amount > :v
@@ -283,23 +280,80 @@ the `KeyConditionExpression` / `ProjectionExpression`.
283
280
 
284
281
  ### Writes
285
282
 
283
+ Raw base-table writes are `putItem` / `updateItem` / `deleteItem` — the primitive
284
+ single-item operations with no lifecycle semantics:
285
+
286
286
  ```ts
287
- await User.put({
287
+ await User.putItem({
288
288
  userId: 'alice',
289
289
  name: 'Alice',
290
290
  email: 'alice@example.com',
291
291
  status: 'active',
292
292
  });
293
293
 
294
- await GroupMembership.put({
294
+ await GroupMembership.putItem({
295
295
  groupId: 'eng',
296
296
  userId: 'alice',
297
297
  role: 'admin',
298
298
  });
299
299
 
300
- await User.update(alice, { status: 'disabled' });
300
+ await User.updateItem({ userId: 'alice' }, { status: 'disabled' });
301
301
  ```
302
302
 
303
+ Lifecycle-aware single writes — conditional gates, read-back, referential
304
+ effects — go through `DDBModel.mutate`, not the raw primitives (see
305
+ [The in-process unified envelope](#the-in-process-unified-envelope) below).
306
+
307
+ ### The in-process unified envelope
308
+
309
+ `DDBModel.query` and `DDBModel.mutate` take a single **alias-map envelope** that
310
+ runs multiple routes in one call. This is the in-process analog of a GraphQL
311
+ operation: each alias is a named route, and the result is keyed by the same
312
+ aliases.
313
+
314
+ `DDBModel.query(map)` runs each read route independently and in parallel — there
315
+ is no cross-route consistency, exactly like GraphQL's parallel field resolution:
316
+
317
+ ```ts
318
+ const { user, members } = await DDBModel.query({
319
+ user: { query: User, key: { userId: 'u1' }, select: { name: true } },
320
+ members: { list: GroupMembership, key: { groupId: 'eng' }, select: { role: true }, options: { limit: 20 } },
321
+ });
322
+ // user: Item | null ; members: { items, cursor }
323
+ ```
324
+
325
+ A read route descriptor is `{ query | list: Model, key, select, options? }`
326
+ (exactly one of `query` / `list`). `options` for `query` is
327
+ `{ consistentRead?, maxDepth? }`; for `list` it is `{ limit?, after?, order?, filter? }`.
328
+
329
+ `DDBModel.mutate(map, { mode })` runs write routes. A write route descriptor is
330
+ `{ create | update | remove: Model, key, input?, condition?, result? }`:
331
+
332
+ ```ts
333
+ const res = await DDBModel.mutate({
334
+ a: { create: GroupMembership, key: { groupId: 'eng', userId: 'u1' }, input: { role: 'admin' } },
335
+ b: { update: User, key: { userId: 'u1' }, input: { name: 'Ann' }, condition: { status: 'active' }, result: { select: { name: true } } },
336
+ }, { mode: 'transaction' });
337
+ ```
338
+
339
+ - **`key`** is a single object or an **array of objects** (key-array bulk). A
340
+ transaction compiles to `TransactWriteItems`; parallel mode compiles to
341
+ `BatchWriteItem` (chunked, with `UnprocessedItems` retry).
342
+ - **`condition`** is an equality subset that gates the write.
343
+ - **`result: { select, options? }`** reads the written item back; omit it and the
344
+ route returns void.
345
+ - **`mode: 'transaction'`** (DEFAULT) is one atomic `TransactWriteItems`:
346
+ all-or-nothing rollback, throws on failure, and a map of more than 25 items
347
+ errors (it is never split). This is GraphQL's all-or-nothing atomic contract.
348
+ - **`mode: 'parallel'`** is non-atomic: each alias reports partial success in the
349
+ result object as `{ ok }` | `{ error }`, mirroring GraphQL's per-field partial
350
+ success. Independent ops run in parallel; dependencies are ordered by
351
+ `$.alias.field` references.
352
+
353
+ In GraphQL terms: a transaction is atomic all-or-nothing; parallel is non-atomic
354
+ per-field partial success; and `query` routes are parallel independent reads with
355
+ no cross-route consistency.
356
+
303
357
  ### Inspect Execution Plans
304
358
 
305
359
  `explain()` shows the DynamoDB operations before they are executed.