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.
- package/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/index.cjs +1908 -0
- package/dist/index.d.cts +639 -0
- package/dist/index.d.ts +639 -0
- package/dist/index.js +1871 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 DynoTable
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# dynamodb-expression-builder
|
|
2
|
+
|
|
3
|
+
DynamoDB expression builder and code generator. Build update, condition, filter and key condition expressions with automatic `ExpressionAttributeNames` / `ExpressionAttributeValues` aliasing — then emit the whole request as runnable code for the JavaScript SDK v3, AWS CLI, boto3 (Python), Java, Go, .NET, PartiQL or [dynamodb-toolbox](https://github.com/dynamodb-toolbox/dynamodb-toolbox). Zero dependencies.
|
|
4
|
+
|
|
5
|
+
Hand-writing DynamoDB expressions means juggling three coupled structures — the expression string, the `#name` aliases (mandatory whenever an attribute name is one of DynamoDB's 573 reserved words), and the typed `:value` placeholders — and keeping them consistent across every operation. The AWS SDKs for [Go](https://docs.aws.amazon.com/sdk-for-go/) and [Java](https://docs.aws.amazon.com/sdk-for-java/) ship expression builders for this; the JavaScript SDK v3 [does not](https://github.com/aws/aws-sdk-js-v3/issues/3165). This package is that builder, plus something the official ones don't do in any language: code generation, so one structured request becomes a paste-ready command in whichever SDK your team actually runs.
|
|
6
|
+
|
|
7
|
+
Values are **type-tagged** (`S`/`N`/`B`/`BOOL`/`SS`/`NS`/`BS`/`NULL`), never inferred from JavaScript runtime types — `marshall('5')` would silently write a string where you meant a number; a tag can't.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npm install dynamodb-expression-builder
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
ESM and CJS, browser-safe, no dependencies.
|
|
16
|
+
|
|
17
|
+
## Thirty seconds
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import {buildRequest, emitSdkV3, emitCli, emitBoto3} from 'dynamodb-expression-builder';
|
|
21
|
+
|
|
22
|
+
const request = buildRequest({
|
|
23
|
+
operation: 'Query',
|
|
24
|
+
tableName: 'orders',
|
|
25
|
+
hashKey: {field: 'customerId', type: 'S', value: 'CUST#42'},
|
|
26
|
+
rangeKey: {field: 'orderDate', type: 'S', operator: 'begins_with', value: '2026-08'},
|
|
27
|
+
filters: [{field: 'status', type: 'S', operator: '=', value: 'shipped'}]
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
emitSdkV3(request);
|
|
31
|
+
// new QueryCommand({
|
|
32
|
+
// "TableName": "orders",
|
|
33
|
+
// "KeyConditionExpression": "#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)",
|
|
34
|
+
// "FilterExpression": "#filter0 = :filterValue0",
|
|
35
|
+
// "ExpressionAttributeNames": {
|
|
36
|
+
// "#hashKey": "customerId",
|
|
37
|
+
// "#rangeKey": "orderDate",
|
|
38
|
+
// "#filter0": "status"
|
|
39
|
+
// },
|
|
40
|
+
// "ExpressionAttributeValues": {
|
|
41
|
+
// ":hashKeyValue": { "S": "CUST#42" },
|
|
42
|
+
// ":rangeKeyValue": { "S": "2026-08" },
|
|
43
|
+
// ":filterValue0": { "S": "shipped" }
|
|
44
|
+
// }
|
|
45
|
+
// })
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The same `request` feeds every emitter — `emitCli(request)` gives the `aws dynamodb query \ …` command, `emitBoto3(request)` the Python, `emitJava` / `emitGo` / `emitDotnet` the typed AttributeValue constructors for those SDKs, and `emitPartiql(request)` the equivalent `SELECT` statement (or an honest `{ok: false, reason}` where PartiQL can't express the request).
|
|
49
|
+
|
|
50
|
+
Update expressions compile from a list of actions:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import {buildUpdateExpression, makeTypedValue} from 'dynamodb-expression-builder';
|
|
54
|
+
|
|
55
|
+
buildUpdateExpression([
|
|
56
|
+
{kind: 'SET', field: 'status', setOp: 'assign', value: makeTypedValue('S', 'shipped')},
|
|
57
|
+
{kind: 'ADD', field: 'loginCount', value: makeTypedValue('N', '1')},
|
|
58
|
+
{kind: 'REMOVE', field: 'legacyFlag'}
|
|
59
|
+
]);
|
|
60
|
+
// {
|
|
61
|
+
// expression: 'SET #upd0 = :updValue0 REMOVE #upd2 ADD #upd1 :updValue1',
|
|
62
|
+
// names: {'#upd0': 'status', '#upd1': 'loginCount', '#upd2': 'legacyFlag'},
|
|
63
|
+
// typedValues: {':updValue0': {type: 'S', value: 'shipped'}, ':updValue1': {type: 'N', value: '1'}}
|
|
64
|
+
// }
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
SET idioms are first-class: `assign`, `if_not_exists`, atomic counters (`add`/`subtract`), `list_append`/`list_prepend`, plus `REMOVE` (including list elements by index) and `ADD`/`DELETE` for numbers and sets.
|
|
68
|
+
|
|
69
|
+
And `emitQueryProgram(config, format)` wraps a Query/Scan request into a complete runnable program — client setup, the request, and a `LastEvaluatedKey` pagination loop — with `format` one of `'sdk' | 'cli' | 'boto3' | 'partiql' | 'java' | 'go' | 'dotnet' | 'ddbtoolbox'`.
|
|
70
|
+
|
|
71
|
+
## API
|
|
72
|
+
|
|
73
|
+
Three layers, each usable on its own:
|
|
74
|
+
|
|
75
|
+
| Layer | Exports |
|
|
76
|
+
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
77
|
+
| Model | `TypedValue`, `makeTypedValue`, `FilterRow`, `KeyAttr`, `RangeKeyCondition`, `UpdateAction`, the `FILTER_OPERATORS` registry + per-type compatibility helpers |
|
|
78
|
+
| Builders | `buildRequest(config)` → one `CanonicalRequest` for any of GetItem/Query/Scan/Update/Put/Delete · `buildFilterExpressions` · `buildKeyConditionExpression` · `buildUpdateExpression` |
|
|
79
|
+
| Emitters | `emitSdkV3` · `emitCli` · `emitBoto3` · `emitJava` · `emitGo` · `emitDotnet` · `emitPartiql` · `emitDdbToolboxProgram` · `emitQueryProgram` · `typedMapToAvMap` (tag-driven marshal) |
|
|
80
|
+
|
|
81
|
+
Placeholder namespaces never collide: keys use `#hashKey`/`#rangeKey`, filters `#filter{i}`, conditions `#cond{i}`, updates `#upd{i}` — one request can carry a key condition, a filter, a write condition and an update expression simultaneously.
|
|
82
|
+
|
|
83
|
+
Honest degradation is a design rule: emitters return `{ok: false, reason}` (PartiQL for unsupported constructs, program emission where a target can't express the request) instead of emitting code that looks right and isn't.
|
|
84
|
+
|
|
85
|
+
## Build one in the browser
|
|
86
|
+
|
|
87
|
+
The same engine powers two interactive tools: the [DynamoDB expression builder](https://dynotable.com/tools/dynamodb-expression-builder) (expression syntax for all six operations) and the [DynamoDB query builder](https://dynotable.com/tools/dynamodb-query-builder) (complete Query/Scan requests with the pagination loop). Reserved-word aliasing is the same problem our [dynamodb-reserved-words](https://github.com/dynotable/dynamodb-reserved-words) package solves as data.
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT © [DynoTable](https://dynotable.com)
|