dynamodb-expression-builder 0.1.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.
@@ -0,0 +1,639 @@
1
+ //#region src/operators.d.ts
2
+ /**
3
+ * Wire-format (uppercase) operator union. INLINED copy of the app's
4
+ * `WireFilterOperator` (`src/schemas/dynamodb-schemas.ts`).
5
+ */
6
+ type WireFilterOperator = 'EQ' | 'NE' | 'GT' | 'GE' | 'LT' | 'LE' | 'CONTAINS' | 'BEGINS_WITH' | 'BETWEEN' | 'IN' | 'EXISTS' | 'NOT_EXISTS' | 'SIZE_EQ' | 'SIZE_NE' | 'SIZE_LT' | 'SIZE_LE' | 'SIZE_GT' | 'SIZE_GE' | 'TYPE_EQ' | 'TYPE_NE';
7
+ /**
8
+ * Data types the compat map reasons about. `L`/`M` are included even though the
9
+ * tool's Type selector doesn't expose them — they keep the compat table a
10
+ * faithful port of the app's (where indexed columns can report List/Map).
11
+ */
12
+ type FilterDataType = 'S' | 'N' | 'B' | 'SS' | 'NS' | 'BS' | 'BOOL' | 'NULL' | 'L' | 'M';
13
+ /**
14
+ * Single source-of-truth row for an operator. One row per operator; consumers
15
+ * read the metadata they need (wire form, value-shape gates, key/scan type
16
+ * compatibility).
17
+ */
18
+ type OperatorDef = {
19
+ readonly value: string;
20
+ readonly label: string;
21
+ readonly symbol: string;
22
+ readonly wireForm: WireFilterOperator;
23
+ /** false → no RHS value (`exists`, `not_exists`). */
24
+ readonly requiresValue: boolean;
25
+ /** true → needs a second RHS value (`between` only). */
26
+ readonly requiresValue2: boolean;
27
+ /** true → type field is optional / defaults to `S` (`exists`, `size_*`). */
28
+ readonly typeOptional: boolean;
29
+ /** Key-eligible types. `[]` → scan-only, rejected by KeyConditionExpression. */
30
+ readonly keyAllowedTypes: ReadonlyArray<'S' | 'N' | 'B'>;
31
+ /** Scan-eligible types. Non-empty. */
32
+ readonly scanAllowedTypes: readonly FilterDataType[];
33
+ };
34
+ declare const FILTER_OPERATORS: readonly [{
35
+ readonly value: "=";
36
+ readonly label: "Equals (=)";
37
+ readonly symbol: "=";
38
+ readonly wireForm: "EQ";
39
+ readonly requiresValue: true;
40
+ readonly requiresValue2: false;
41
+ readonly typeOptional: false;
42
+ readonly keyAllowedTypes: readonly ["S", "N", "B"];
43
+ readonly scanAllowedTypes: readonly ["S", "N", "B", "SS", "NS", "BS", "BOOL", "NULL", "L", "M"];
44
+ }, {
45
+ readonly value: "<>";
46
+ readonly label: "Not Equals (≠)";
47
+ readonly symbol: "≠";
48
+ readonly wireForm: "NE";
49
+ readonly requiresValue: true;
50
+ readonly requiresValue2: false;
51
+ readonly typeOptional: false;
52
+ readonly keyAllowedTypes: readonly [];
53
+ readonly scanAllowedTypes: readonly ["S", "N", "B", "SS", "NS", "BS", "BOOL", "NULL", "L", "M"];
54
+ }, {
55
+ readonly value: "<";
56
+ readonly label: "Less Than (<)";
57
+ readonly symbol: "<";
58
+ readonly wireForm: "LT";
59
+ readonly requiresValue: true;
60
+ readonly requiresValue2: false;
61
+ readonly typeOptional: false;
62
+ readonly keyAllowedTypes: readonly ["N"];
63
+ readonly scanAllowedTypes: readonly ["N"];
64
+ }, {
65
+ readonly value: "<=";
66
+ readonly label: "Less Than or Equal (≤)";
67
+ readonly symbol: "≤";
68
+ readonly wireForm: "LE";
69
+ readonly requiresValue: true;
70
+ readonly requiresValue2: false;
71
+ readonly typeOptional: false;
72
+ readonly keyAllowedTypes: readonly ["N"];
73
+ readonly scanAllowedTypes: readonly ["N"];
74
+ }, {
75
+ readonly value: ">";
76
+ readonly label: "Greater Than (>)";
77
+ readonly symbol: ">";
78
+ readonly wireForm: "GT";
79
+ readonly requiresValue: true;
80
+ readonly requiresValue2: false;
81
+ readonly typeOptional: false;
82
+ readonly keyAllowedTypes: readonly ["N"];
83
+ readonly scanAllowedTypes: readonly ["N"];
84
+ }, {
85
+ readonly value: ">=";
86
+ readonly label: "Greater Than or Equal (≥)";
87
+ readonly symbol: "≥";
88
+ readonly wireForm: "GE";
89
+ readonly requiresValue: true;
90
+ readonly requiresValue2: false;
91
+ readonly typeOptional: false;
92
+ readonly keyAllowedTypes: readonly ["N"];
93
+ readonly scanAllowedTypes: readonly ["N"];
94
+ }, {
95
+ readonly value: "contains";
96
+ readonly label: "Contains";
97
+ readonly symbol: "∋";
98
+ readonly wireForm: "CONTAINS";
99
+ readonly requiresValue: true;
100
+ readonly requiresValue2: false;
101
+ readonly typeOptional: false;
102
+ readonly keyAllowedTypes: readonly [];
103
+ readonly scanAllowedTypes: readonly ["S", "B", "SS", "NS", "BS", "L"];
104
+ }, {
105
+ readonly value: "begins_with";
106
+ readonly label: "Begins With";
107
+ readonly symbol: "^";
108
+ readonly wireForm: "BEGINS_WITH";
109
+ readonly requiresValue: true;
110
+ readonly requiresValue2: false;
111
+ readonly typeOptional: false;
112
+ readonly keyAllowedTypes: readonly ["S", "B"];
113
+ readonly scanAllowedTypes: readonly ["S", "B"];
114
+ }, {
115
+ readonly value: "between";
116
+ readonly label: "Between";
117
+ readonly symbol: "↔";
118
+ readonly wireForm: "BETWEEN";
119
+ readonly requiresValue: true;
120
+ readonly requiresValue2: true;
121
+ readonly typeOptional: false;
122
+ readonly keyAllowedTypes: readonly ["N"];
123
+ readonly scanAllowedTypes: readonly ["N"];
124
+ }, {
125
+ readonly value: "in";
126
+ readonly label: "In";
127
+ readonly symbol: "∈";
128
+ readonly wireForm: "IN";
129
+ readonly requiresValue: true;
130
+ readonly requiresValue2: false;
131
+ readonly typeOptional: false;
132
+ readonly keyAllowedTypes: readonly [];
133
+ readonly scanAllowedTypes: readonly ["S", "N"];
134
+ }, {
135
+ readonly value: "exists";
136
+ readonly label: "Attribute Exists";
137
+ readonly symbol: "∃";
138
+ readonly wireForm: "EXISTS";
139
+ readonly requiresValue: false;
140
+ readonly requiresValue2: false;
141
+ readonly typeOptional: true;
142
+ readonly keyAllowedTypes: readonly [];
143
+ readonly scanAllowedTypes: readonly ["S", "N", "B", "SS", "NS", "BS", "BOOL", "NULL", "L", "M"];
144
+ }, {
145
+ readonly value: "not_exists";
146
+ readonly label: "Attribute Not Exists";
147
+ readonly symbol: "∄";
148
+ readonly wireForm: "NOT_EXISTS";
149
+ readonly requiresValue: false;
150
+ readonly requiresValue2: false;
151
+ readonly typeOptional: true;
152
+ readonly keyAllowedTypes: readonly [];
153
+ readonly scanAllowedTypes: readonly ["S", "N", "B", "SS", "NS", "BS", "BOOL", "NULL", "L", "M"];
154
+ }, {
155
+ readonly value: "size_eq";
156
+ readonly label: "Size Equals";
157
+ readonly symbol: "size =";
158
+ readonly wireForm: "SIZE_EQ";
159
+ readonly requiresValue: true;
160
+ readonly requiresValue2: false;
161
+ readonly typeOptional: true;
162
+ readonly keyAllowedTypes: readonly [];
163
+ readonly scanAllowedTypes: readonly ["SS", "NS", "BS", "L", "M"];
164
+ }, {
165
+ readonly value: "size_ne";
166
+ readonly label: "Size Not Equals";
167
+ readonly symbol: "size ≠";
168
+ readonly wireForm: "SIZE_NE";
169
+ readonly requiresValue: true;
170
+ readonly requiresValue2: false;
171
+ readonly typeOptional: true;
172
+ readonly keyAllowedTypes: readonly [];
173
+ readonly scanAllowedTypes: readonly ["SS", "NS", "BS", "L", "M"];
174
+ }, {
175
+ readonly value: "size_lt";
176
+ readonly label: "Size Less Than";
177
+ readonly symbol: "size <";
178
+ readonly wireForm: "SIZE_LT";
179
+ readonly requiresValue: true;
180
+ readonly requiresValue2: false;
181
+ readonly typeOptional: true;
182
+ readonly keyAllowedTypes: readonly [];
183
+ readonly scanAllowedTypes: readonly ["SS", "NS", "BS", "L", "M"];
184
+ }, {
185
+ readonly value: "size_le";
186
+ readonly label: "Size Less Than or Equal";
187
+ readonly symbol: "size ≤";
188
+ readonly wireForm: "SIZE_LE";
189
+ readonly requiresValue: true;
190
+ readonly requiresValue2: false;
191
+ readonly typeOptional: true;
192
+ readonly keyAllowedTypes: readonly [];
193
+ readonly scanAllowedTypes: readonly ["SS", "NS", "BS", "L", "M"];
194
+ }, {
195
+ readonly value: "size_gt";
196
+ readonly label: "Size Greater Than";
197
+ readonly symbol: "size >";
198
+ readonly wireForm: "SIZE_GT";
199
+ readonly requiresValue: true;
200
+ readonly requiresValue2: false;
201
+ readonly typeOptional: true;
202
+ readonly keyAllowedTypes: readonly [];
203
+ readonly scanAllowedTypes: readonly ["SS", "NS", "BS", "L", "M"];
204
+ }, {
205
+ readonly value: "size_ge";
206
+ readonly label: "Size Greater Than or Equal";
207
+ readonly symbol: "size ≥";
208
+ readonly wireForm: "SIZE_GE";
209
+ readonly requiresValue: true;
210
+ readonly requiresValue2: false;
211
+ readonly typeOptional: true;
212
+ readonly keyAllowedTypes: readonly [];
213
+ readonly scanAllowedTypes: readonly ["SS", "NS", "BS", "L", "M"];
214
+ }, {
215
+ readonly value: "type_eq";
216
+ readonly label: "Type Equals";
217
+ readonly symbol: "type =";
218
+ readonly wireForm: "TYPE_EQ";
219
+ readonly requiresValue: true;
220
+ readonly requiresValue2: false;
221
+ readonly typeOptional: false;
222
+ readonly keyAllowedTypes: readonly [];
223
+ readonly scanAllowedTypes: readonly ["S", "N", "B", "SS", "NS", "BS", "BOOL", "NULL", "L", "M"];
224
+ }, {
225
+ readonly value: "type_ne";
226
+ readonly label: "Type Not Equals";
227
+ readonly symbol: "type ≠";
228
+ readonly wireForm: "TYPE_NE";
229
+ readonly requiresValue: true;
230
+ readonly requiresValue2: false;
231
+ readonly typeOptional: false;
232
+ readonly keyAllowedTypes: readonly [];
233
+ readonly scanAllowedTypes: readonly ["S", "N", "B", "SS", "NS", "BS", "BOOL", "NULL", "L", "M"];
234
+ }];
235
+ /** Tightened union of every operator's lowercase internal value. */
236
+ type OperatorValue = (typeof FILTER_OPERATORS)[number]['value'];
237
+ /**
238
+ * O(1) registry lookup. Loose-keyed (`Record<string, OperatorDef>`) so boundary
239
+ * callers must guard `if (!def)` — the runtime value is `undefined` for unknown
240
+ * keys.
241
+ */
242
+ declare const OPERATOR_BY_VALUE: Readonly<Record<string, OperatorDef>>;
243
+ /** Key-eligible operators (KeyConditionExpression compatible). */
244
+ declare const KEY_OPERATORS: readonly OperatorDef[];
245
+ type FilterOperatorOption = (typeof FILTER_OPERATORS)[number];
246
+ /**
247
+ * Operators applicable to a scan value of the given type. Undefined type → full
248
+ * list. Filters/conditions use this.
249
+ */
250
+ declare function getCompatibleFilterOperators(type: FilterDataType | undefined): readonly FilterOperatorOption[];
251
+ /**
252
+ * Key-eligible operators compatible with the given key type. Undefined → full
253
+ * key list. Range-key UI uses this (type-gated: N gets `<`/`between`, S/B get
254
+ * `begins_with`, all keys get `=`).
255
+ */
256
+ declare function getCompatibleComparisonOperators(type: 'S' | 'N' | 'B' | undefined): readonly OperatorDef[];
257
+ //#endregion
258
+ //#region src/types.d.ts
259
+ /**
260
+ * Value type tags the tool exposes. Mirrors the app's filter Type selector
261
+ * minus `L`/`M` (no nested List/Map in v1 — see docs/plans/…expression-builder).
262
+ */
263
+ type DdbScalarType = 'S' | 'N' | 'B' | 'BOOL' | 'SS' | 'NS' | 'BS' | 'NULL';
264
+ /** The set-typed tags, which carry members in `values` rather than `value`. */
265
+ declare const SET_TYPES: readonly ["SS", "NS", "BS"];
266
+ type SetType = (typeof SET_TYPES)[number];
267
+ declare function isSetType(type: DdbScalarType): type is SetType;
268
+ /**
269
+ * The scalar element type of a set tag (SS→S, NS→N, BS→B); identity for every
270
+ * scalar. `contains(path, operand)` takes a SCALAR operand even when `path` is a
271
+ * set (it tests membership), so the set-typed tag must marshal its ELEMENT type
272
+ * there — never `{SS:[…]}`, which DynamoDB rejects.
273
+ */
274
+ declare function elementType(type: DdbScalarType): DdbScalarType;
275
+ /**
276
+ * A value carried with its DynamoDB type tag. `value` holds the scalar string
277
+ * representation (S text; N numeric string; B base64; BOOL `'true'`/`'false'`;
278
+ * NULL unused). `values` holds the members of a set type (SS/NS/BS). Exactly
279
+ * one is meaningful per `type`; emitters branch on the tag, not the runtime.
280
+ */
281
+ interface TypedValue {
282
+ type: DdbScalarType;
283
+ value: string;
284
+ /** Members for set types (SS/NS/BS). Undefined for scalars. */
285
+ values?: string[];
286
+ }
287
+ /**
288
+ * Build a {@link TypedValue} from a tag + raw entry. Set types take an explicit
289
+ * member array (falling back to the single `value` as one member); scalars take
290
+ * the string; NULL ignores the payload.
291
+ */
292
+ declare function makeTypedValue(type: DdbScalarType, value: string, values?: string[]): TypedValue;
293
+ /**
294
+ * A filter (Scan/Query) or condition (Update/Put/Delete) predicate row, as the
295
+ * bespoke UI emits it. `operator` is the lowercase internal value from
296
+ * `operators.ts` (`'='`, `'begins_with'`, …); the builder maps it to its wire
297
+ * form before compiling. `type` tags the RHS value(s).
298
+ */
299
+ interface FilterRow {
300
+ field: string;
301
+ operator: OperatorValue;
302
+ type: DdbScalarType;
303
+ /** RHS scalar (unused for `exists`/`not_exists`; first bound for `between`). */
304
+ value: string;
305
+ /** Second bound for `between`. */
306
+ value2?: string;
307
+ /** Members for `in` (and set-typed single comparisons). */
308
+ values?: string[];
309
+ }
310
+ /** A primary-key attribute (GetItem/Delete Key map; Query hash key). */
311
+ interface KeyAttr {
312
+ field: string;
313
+ /** Keys are always scalar S/N/B, but typed as the full union for reuse. */
314
+ type: DdbScalarType;
315
+ value: string;
316
+ }
317
+ /** Query range-key condition (a key-eligible operator + value[s]). */
318
+ interface RangeKeyCondition {
319
+ field: string;
320
+ type: DdbScalarType;
321
+ operator: OperatorValue;
322
+ value: string;
323
+ /** Second bound for `between`. */
324
+ value2?: string;
325
+ }
326
+ /** A Put item attribute carrying its type tag. */
327
+ interface ItemAttr {
328
+ field: string;
329
+ type: DdbScalarType;
330
+ value: string;
331
+ /** Members for set types. */
332
+ values?: string[];
333
+ }
334
+ /** SET-clause idioms (the only action kind with sub-modes). */
335
+ type SetOperation = 'assign' | 'if_not_exists' | 'add' | 'subtract' | 'list_append' | 'list_prepend';
336
+ type UpdateActionKind = 'SET' | 'REMOVE' | 'ADD' | 'DELETE';
337
+ /**
338
+ * A single UpdateExpression action. `SET` carries a `setOp` idiom; `REMOVE`
339
+ * targets an attribute (optionally a list element via `index`); `ADD`/`DELETE`
340
+ * carry a number (ADD) or set (ADD/DELETE) value.
341
+ */
342
+ interface UpdateAction {
343
+ kind: UpdateActionKind;
344
+ field: string;
345
+ /** SET only: which SET idiom. */
346
+ setOp?: SetOperation;
347
+ /** RHS value (SET except plain index removal; ADD; DELETE). */
348
+ value?: TypedValue;
349
+ /** List-element index for REMOVE (`#a[2]`). */
350
+ index?: number;
351
+ }
352
+ /** The six operations the builder supports. */
353
+ type DdbOperation = 'GetItem' | 'Query' | 'Scan' | 'Update' | 'Put' | 'Delete';
354
+ /**
355
+ * The whole builder state — one config covering every operation. Sub-parts are
356
+ * optional; `buildRequest` reads only the ones an operation uses (GetItem→key;
357
+ * Query→hashKey[+rangeKey][+filters]; Scan→filters; Update→key+updates[+conditions];
358
+ * Put→item[+conditions]; Delete→key[+conditions]). Serialised whole into the
359
+ * single `state` URL param.
360
+ */
361
+ interface BuilderConfig {
362
+ operation: DdbOperation;
363
+ tableName: string;
364
+ indexName?: string;
365
+ /**
366
+ * Base-table PK/SK NAMES + TYPES only (never values). Lets a Scan or GSI-query
367
+ * emitter scaffold the table's REAL key schema instead of a `// TODO`
368
+ * placeholder — the request's own key belongs to the GSI (or is absent for a
369
+ * Scan), so the base schema must ride along separately. Absent when the base
370
+ * schema isn't known (the stateless expression tool, or table info not yet
371
+ * loaded); emitters fall back to the placeholder then.
372
+ */
373
+ baseKeySchema?: {
374
+ hashKey: {
375
+ field: string;
376
+ type: DdbScalarType;
377
+ };
378
+ rangeKey?: {
379
+ field: string;
380
+ type: DdbScalarType;
381
+ };
382
+ };
383
+ /** Query hash key (EQ). */
384
+ hashKey?: KeyAttr;
385
+ /** Query range key condition. */
386
+ rangeKey?: RangeKeyCondition;
387
+ /** GetItem/Update/Delete exact primary key attrs (hash[+range]). */
388
+ key?: KeyAttr[];
389
+ /** Scan/Query filter predicates. */
390
+ filters?: FilterRow[];
391
+ /** Update/Put/Delete write conditions. */
392
+ conditions?: FilterRow[];
393
+ /** Update actions. */
394
+ updates?: UpdateAction[];
395
+ /** Put item attributes. */
396
+ item?: ItemAttr[];
397
+ /** GetItem/Query/Scan projected attribute names. */
398
+ projection?: string[];
399
+ /** Query/Scan `Limit` — max items EVALUATED per request (positive integer). */
400
+ limit?: number;
401
+ /**
402
+ * Query sort order. Only `false` (descending) is carried through — `true` is
403
+ * the DynamoDB default, and emitting it would just be noise in the snippet.
404
+ */
405
+ scanIndexForward?: boolean;
406
+ /** GetItem/Query/Scan strongly-consistent read (only `true` is carried). */
407
+ consistentRead?: boolean;
408
+ /**
409
+ * Query/Scan resume point — the `LastEvaluatedKey` of a previous page, as
410
+ * typed key attrs (hash[+range]). Compiled into `ExclusiveStartKey`.
411
+ */
412
+ exclusiveStartKey?: KeyAttr[];
413
+ }
414
+ /**
415
+ * The canonical, fully-resolved request every emitter formats. Expression
416
+ * strings reference `#`/`:` placeholders resolved by `names`/`typedValues`;
417
+ * empty maps are omitted. `key`/`item` are direct name→value maps (no
418
+ * placeholders). `config` is the raw model retained for PartiQL, which builds
419
+ * literals rather than placeholders.
420
+ */
421
+ interface CanonicalRequest {
422
+ operation: DdbOperation;
423
+ tableName: string;
424
+ indexName?: string;
425
+ key?: Record<string, TypedValue>;
426
+ item?: Record<string, TypedValue>;
427
+ keyConditionExpression?: string;
428
+ filterExpression?: string;
429
+ updateExpression?: string;
430
+ conditionExpression?: string;
431
+ projectionExpression?: string;
432
+ names?: Record<string, string>;
433
+ typedValues?: Record<string, TypedValue>;
434
+ /** Query/Scan `Limit` (positive integer; present only when set). */
435
+ limit?: number;
436
+ /** Present ONLY as `false` (descending Query) — the default `true` is omitted. */
437
+ scanIndexForward?: boolean;
438
+ /** Present ONLY as `true` (strongly-consistent read). */
439
+ consistentRead?: boolean;
440
+ /** Query/Scan resume point (typed name→value map, like `key`). */
441
+ exclusiveStartKey?: Record<string, TypedValue>;
442
+ config: BuilderConfig;
443
+ }
444
+ //#endregion
445
+ //#region src/filter-expressions.d.ts
446
+ /** Namespacing prefix so filter and condition placeholders never collide. */
447
+ type PredicatePrefix = 'filter' | 'cond';
448
+ interface PredicateExpression {
449
+ expression: string;
450
+ names: Record<string, string>;
451
+ typedValues: Record<string, TypedValue>;
452
+ }
453
+ /**
454
+ * Compile a list of predicate rows into one `… AND …` expression plus the
455
+ * fresh names/typedValues maps it references. Returns null for an empty list.
456
+ * Callers (buildRequest) merge the maps; this function never mutates shared
457
+ * state.
458
+ */
459
+ declare function buildFilterExpressions(rows: FilterRow[], prefix: PredicatePrefix): PredicateExpression | null;
460
+ //#endregion
461
+ //#region src/key-command.d.ts
462
+ interface KeyConditionResult {
463
+ expression: string;
464
+ names: Record<string, string>;
465
+ typedValues: Record<string, TypedValue>;
466
+ }
467
+ /**
468
+ * Build a Query KeyConditionExpression from a hash key (always EQ) plus an
469
+ * optional range-key condition. Captures value types.
470
+ */
471
+ declare function buildKeyConditionExpression(hashKey: KeyAttr, rangeKey?: RangeKeyCondition): KeyConditionResult;
472
+ /**
473
+ * Build the plain typed Key map (GetItem/Update/Delete) — real attribute names
474
+ * mapped to typed values, no expression placeholders.
475
+ */
476
+ declare function buildKeyMap(keys: KeyAttr[]): Record<string, TypedValue>;
477
+ //#endregion
478
+ //#region src/build-request.d.ts
479
+ /**
480
+ * Assemble a {@link CanonicalRequest} from a builder config. Pure: reads only the
481
+ * config sub-parts the operation uses, merges the sub-builders' maps, and omits
482
+ * any map that ended up empty. Throws (fail loud) when a required part is missing
483
+ * (a Query without a hash key) rather than emitting a malformed request.
484
+ */
485
+ declare function buildRequest(config: BuilderConfig): CanonicalRequest;
486
+ //#endregion
487
+ //#region src/build-update-expression.d.ts
488
+ interface UpdateExpressionResult {
489
+ expression: string;
490
+ names: Record<string, string>;
491
+ typedValues: Record<string, TypedValue>;
492
+ }
493
+ /**
494
+ * Compile update actions into one UpdateExpression. Returns null for an empty
495
+ * list. Callers (buildRequest) merge the returned maps; this never mutates
496
+ * shared state. Actions are grouped by kind into the canonical
497
+ * `SET … REMOVE … ADD … DELETE …` order while preserving each action's input
498
+ * order within its clause.
499
+ */
500
+ declare function buildUpdateExpression(actions: UpdateAction[]): UpdateExpressionResult | null;
501
+ //#endregion
502
+ //#region src/emit/marshal.d.ts
503
+ /** A single DynamoDB-JSON AttributeValue (the v1 scalar/set subset). */
504
+ type AttributeValue = {
505
+ S: string;
506
+ } | {
507
+ N: string;
508
+ } | {
509
+ B: string;
510
+ } | {
511
+ BOOL: boolean;
512
+ } | {
513
+ SS: string[];
514
+ } | {
515
+ NS: string[];
516
+ } | {
517
+ BS: string[];
518
+ } | {
519
+ NULL: true;
520
+ };
521
+ /** Build an AttributeValue from a value's type tag (not its runtime type). */
522
+ declare function typedValueToAv(tv: TypedValue): AttributeValue;
523
+ /** Marshal a whole placeholder/attr map (`:v`→typed, or name→typed) to AVs. */
524
+ declare function typedMapToAvMap(map: Record<string, TypedValue>): Record<string, AttributeValue>;
525
+ /**
526
+ * Does this request carry any binary (`B`/`BS`) value? The SDK v3 / boto3
527
+ * emitters use this to decide whether to emit binary-decoding (a `Uint8Array`
528
+ * expression / an `import base64`).
529
+ */
530
+ declare function hasBinaryValue(request: CanonicalRequest): boolean;
531
+ //#endregion
532
+ //#region src/emit/sdk-v3.d.ts
533
+ /** Build the command params object (key order matches typical SDK usage). */
534
+ declare function buildSdkV3Params(request: CanonicalRequest): Record<string, unknown>;
535
+ /** Emit the `new <Op>Command({...})` source snippet for a canonical request. */
536
+ declare function emitSdkV3(request: CanonicalRequest): string;
537
+ /** The `@aws-sdk/client-dynamodb` command class name for an operation. */
538
+ declare function sdkV3CommandName(operation: DdbOperation): string;
539
+ /**
540
+ * Render an arbitrary params value as the same pretty-printed JS literal
541
+ * `emitSdkV3` embeds (B/BS members as `Uint8Array` expressions). Exported for
542
+ * the query-builder program emitter, which composes its own statements around
543
+ * the literal (client init + pagination loop) instead of a bare `new Command`.
544
+ */
545
+ declare function renderJsValue(value: unknown, indent?: number): string;
546
+ //#endregion
547
+ //#region src/emit/cli.d.ts
548
+ /** Emit the multi-line `aws dynamodb <op>` command for a canonical request. */
549
+ declare function emitCli(request: CanonicalRequest): string;
550
+ //#endregion
551
+ //#region src/emit/boto3.d.ts
552
+ /**
553
+ * Render a params value as the same Python literal `emitBoto3` embeds
554
+ * (`True`/`False`/`None`, B/BS as `base64.b64decode(...)`). Exported for the
555
+ * query-builder program emitter, which renders a `params` dict for its
556
+ * LastEvaluatedKey pagination loop.
557
+ */
558
+ declare function renderPyValue(value: unknown): string;
559
+ /** The low-level boto3 client method name for an operation. */
560
+ declare function boto3MethodName(operation: DdbOperation): string;
561
+ /** Emit the runnable boto3 snippet (client + method call) for a canonical request. */
562
+ declare function emitBoto3(request: CanonicalRequest): string;
563
+ //#endregion
564
+ //#region src/emit/partiql.d.ts
565
+ /** Either a finished statement or an honest reason PartiQL can't express it. */
566
+ type PartiqlResult = {
567
+ ok: true;
568
+ statement: string;
569
+ } | {
570
+ ok: false;
571
+ reason: string;
572
+ };
573
+ /**
574
+ * Emit a PartiQL statement for a canonical request, or an honest
575
+ * `{ ok: false, reason }` when the request has no faithful PartiQL form.
576
+ */
577
+ declare function emitPartiql(request: CanonicalRequest): PartiqlResult;
578
+ //#endregion
579
+ //#region src/emit/java.d.ts
580
+ /** The model request class name for an operation (`QueryRequest`, …). */
581
+ declare function javaRequestClassName(operation: DdbOperation): string;
582
+ /** The `DynamoDbClient` method name for an operation (`query`, …). */
583
+ declare function javaClientMethodName(operation: DdbOperation): string;
584
+ /** Emit the bare `<Op>Request.builder()…build()` snippet for a canonical request. */
585
+ declare function emitJava(request: CanonicalRequest): string;
586
+ //#endregion
587
+ //#region src/emit/go.d.ts
588
+ /** The `dynamodb.<Op>Input` struct name for an operation. */
589
+ declare function goInputTypeName(operation: DdbOperation): string;
590
+ /** The `dynamodb.Client` method name for an operation. */
591
+ declare function goClientMethodName(operation: DdbOperation): string;
592
+ /** Emit the bare `&dynamodb.<Op>Input{…}` snippet for a canonical request. */
593
+ declare function emitGo(request: CanonicalRequest): string;
594
+ //#endregion
595
+ //#region src/emit/dotnet.d.ts
596
+ /** The model request class name for an operation (`QueryRequest`, …). */
597
+ declare function dotnetRequestClassName(operation: DdbOperation): string;
598
+ /** The async client method name for an operation (`QueryAsync`, …). */
599
+ declare function dotnetClientMethodName(operation: DdbOperation): string;
600
+ /** Emit the bare `new <Op>Request { … }` snippet for a canonical request. */
601
+ declare function emitDotnet(request: CanonicalRequest): string;
602
+ //#endregion
603
+ //#region src/emit/ddbtoolbox.d.ts
604
+ /**
605
+ * Emit the runnable dynamodb-toolbox program for a Query/Scan canonical request.
606
+ * `paginate` wraps the send in a `LastEvaluatedKey` loop (dynamodb-toolbox's
607
+ * `send()` returns `{ Items, LastEvaluatedKey }` and takes `exclusiveStartKey`).
608
+ */
609
+ declare function emitDdbToolboxProgram(request: CanonicalRequest, paginate: boolean): string;
610
+ //#endregion
611
+ //#region src/program.d.ts
612
+ /**
613
+ * The query tool's whole state: a Query/Scan {@link BuilderConfig} plus the one
614
+ * PROGRAM-level knob the request itself doesn't carry — whether the emitted
615
+ * code loops on `LastEvaluatedKey` to fetch every page.
616
+ */
617
+ interface QueryToolConfig extends BuilderConfig {
618
+ /** Emit the fetch-all-pages pagination loop (default: single request). */
619
+ paginate?: boolean;
620
+ }
621
+ type QueryProgramFormat = 'sdk' | 'cli' | 'boto3' | 'partiql' | 'java' | 'go' | 'dotnet' | 'ddbtoolbox';
622
+ /** A runnable program, or an honest reason the format can't express it. */
623
+ type ProgramResult = {
624
+ ok: true;
625
+ code: string;
626
+ } | {
627
+ ok: false;
628
+ reason: string;
629
+ };
630
+ /**
631
+ * Emit the runnable program for a Query/Scan config in the given format.
632
+ * Throws on a non-read operation (the widget never produces one — programmer
633
+ * error, mirroring `buildRequest`'s fail-loud posture) and propagates
634
+ * `buildRequest`'s build errors (e.g. a Query without a hash key) for the
635
+ * caller to surface as a note.
636
+ */
637
+ declare function emitQueryProgram(config: QueryToolConfig, format: QueryProgramFormat): ProgramResult;
638
+ //#endregion
639
+ export { type AttributeValue, type BuilderConfig, type CanonicalRequest, type DdbOperation, type DdbScalarType, FILTER_OPERATORS, type FilterDataType, type FilterOperatorOption, type FilterRow, type ItemAttr, KEY_OPERATORS, type KeyAttr, type KeyConditionResult, OPERATOR_BY_VALUE, type OperatorDef, type OperatorValue, type PartiqlResult, type PredicateExpression, type PredicatePrefix, type ProgramResult, type QueryProgramFormat, type QueryToolConfig, type RangeKeyCondition, SET_TYPES, type SetOperation, type SetType, type TypedValue, type UpdateAction, type UpdateExpressionResult, type WireFilterOperator, boto3MethodName, buildFilterExpressions, buildKeyConditionExpression, buildKeyMap, buildRequest, buildSdkV3Params, buildUpdateExpression, dotnetClientMethodName, dotnetRequestClassName, elementType, emitBoto3, emitCli, emitDdbToolboxProgram, emitDotnet, emitGo, emitJava, emitPartiql, emitQueryProgram, emitSdkV3, getCompatibleComparisonOperators, getCompatibleFilterOperators, goClientMethodName, goInputTypeName, hasBinaryValue, isSetType, javaClientMethodName, javaRequestClassName, makeTypedValue, renderJsValue, renderPyValue, sdkV3CommandName, typedMapToAvMap, typedValueToAv };