dynoquery 0.1.19 → 0.1.22
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 +97 -12
- package/dist/expression-builder.d.ts +41 -0
- package/dist/expression-builder.js +248 -0
- package/dist/index-query.d.ts +5 -3
- package/dist/index-query.js +10 -3
- package/dist/index.d.ts +10 -0
- package/dist/index.js +161 -15
- package/dist/partition.d.ts +32 -7
- package/dist/partition.js +84 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -188,16 +188,16 @@ DynoQuery provides `batchWrite` and `batchRead` for processing multiple items ac
|
|
|
188
188
|
|
|
189
189
|
```typescript
|
|
190
190
|
// 1. Batch Write (Create/Replace multiple items)
|
|
191
|
-
const user1 = db.User('john', 'METADATA');
|
|
191
|
+
const user1 = db.User('john@example.com', 'METADATA');
|
|
192
192
|
user1.name = 'John Doe';
|
|
193
193
|
|
|
194
|
-
const user2 = db.User('jane', 'METADATA');
|
|
194
|
+
const user2 = db.User('jane@example.com', 'METADATA');
|
|
195
195
|
user2.name = 'Jane Doe';
|
|
196
196
|
|
|
197
197
|
await db.batchWrite([user1, user2]);
|
|
198
198
|
|
|
199
199
|
// 2. Batch Read (Fetch multiple items or index queries)
|
|
200
|
-
const userDraft = db.User('john', 'METADATA');
|
|
200
|
+
const userDraft = db.User('john@example.com', 'METADATA');
|
|
201
201
|
const categoryQuery = db.findByCategory('ELECTRONICS', 'p123');
|
|
202
202
|
|
|
203
203
|
const results = await db.batchRead([userDraft, categoryQuery]);
|
|
@@ -209,6 +209,37 @@ results.forEach(item => {
|
|
|
209
209
|
item.save(); // Second-level methods are available
|
|
210
210
|
}
|
|
211
211
|
});
|
|
212
|
+
|
|
213
|
+
// 3. Batch Delete
|
|
214
|
+
const userToDelete = db.User('john@example.com').draftDelete('METADATA');
|
|
215
|
+
await db.batchWrite([userToDelete]);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 5. Transaction Operations
|
|
219
|
+
|
|
220
|
+
DynoQuery supports `transactWrite` and `transactRead` for atomic operations across multiple items.
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// 1. Transaction Write (All operations succeed or all fail)
|
|
224
|
+
const user1 = db.User('john@example.com', 'METADATA');
|
|
225
|
+
user1.name = 'John Doe';
|
|
226
|
+
|
|
227
|
+
const userToDelete = db.User('olduser@example.com').draftDelete('METADATA');
|
|
228
|
+
|
|
229
|
+
// You can even set conditions for items in a transaction
|
|
230
|
+
const criticalItem = db.User('admin@example.com', 'METADATA');
|
|
231
|
+
criticalItem.lastLogin = new Date().toISOString();
|
|
232
|
+
criticalItem.setCondition(attr('status').equals('ACTIVE'));
|
|
233
|
+
|
|
234
|
+
await db.transactWrite([user1, userToDelete, criticalItem]);
|
|
235
|
+
|
|
236
|
+
// 2. Transaction Read (Read multiple items atomically)
|
|
237
|
+
const userDraft = db.User('john@example.com', 'METADATA');
|
|
238
|
+
const items = await db.transactRead([userDraft]);
|
|
239
|
+
|
|
240
|
+
if (items[0]) {
|
|
241
|
+
console.log('Found user:', items[0].name);
|
|
242
|
+
}
|
|
212
243
|
```
|
|
213
244
|
|
|
214
245
|
## Optional Configuration Parameters
|
|
@@ -255,6 +286,55 @@ if (token) {
|
|
|
255
286
|
}
|
|
256
287
|
```
|
|
257
288
|
|
|
289
|
+
### Expression Builder (Filters & Conditions)
|
|
290
|
+
|
|
291
|
+
Use `ExpressionBuilder` to build complex filter and condition expressions in a type-safe way.
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
import { attr, ExpressionBuilder } from 'dynoquery';
|
|
295
|
+
|
|
296
|
+
// 1. Filtering in queries
|
|
297
|
+
const builder = attr('age').greaterThan(25).and(attr('status').equals('ACTIVE'));
|
|
298
|
+
const activeUsers = await db.User('some-id').getAll({ filterBuilder: builder });
|
|
299
|
+
|
|
300
|
+
// 2. Conditional Updates
|
|
301
|
+
const johnMeta = db.User('john@example.com', 'METADATA');
|
|
302
|
+
const condition = attr('version').equals(1);
|
|
303
|
+
|
|
304
|
+
johnMeta.setCondition(condition);
|
|
305
|
+
johnMeta.name = 'John New Name';
|
|
306
|
+
johnMeta.version = 2;
|
|
307
|
+
|
|
308
|
+
await johnMeta.save(); // Fails if version is not 1
|
|
309
|
+
|
|
310
|
+
// 3. Raw Condition Expressions
|
|
311
|
+
await db.User('john@example.com').update({ status: 'INACTIVE' }, [], {
|
|
312
|
+
ConditionExpression: '#v = :v',
|
|
313
|
+
ExpressionAttributeNames: { '#v': 'version' },
|
|
314
|
+
ExpressionAttributeValues: { ':v': 2 }
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// Or using Item object
|
|
318
|
+
johnMeta.setCondition(attr('name').exists());
|
|
319
|
+
await johnMeta.save();
|
|
320
|
+
|
|
321
|
+
// 4. Supported Operators
|
|
322
|
+
// - attr('name').equals('val') / notEquals('val')
|
|
323
|
+
// - .lessThan(val) / lessThanOrEqual(val)
|
|
324
|
+
// - .greaterThan(val) / greaterThanOrEqual(val)
|
|
325
|
+
// - .between(start, end)
|
|
326
|
+
// - .in([val1, val2])
|
|
327
|
+
// - logical: .and(otherBuilder), .or(otherBuilder), ExpressionBuilder.not(builder)
|
|
328
|
+
|
|
329
|
+
// 4. Supported Functions
|
|
330
|
+
// - attr('field').exists()
|
|
331
|
+
// - attr('field').notExists()
|
|
332
|
+
// - attr('field').type('S')
|
|
333
|
+
// - attr('field').beginsWith('prefix')
|
|
334
|
+
// - attr('field').contains('value')
|
|
335
|
+
// - attr('field').size().greaterThan(5)
|
|
336
|
+
```
|
|
337
|
+
|
|
258
338
|
## API Reference
|
|
259
339
|
|
|
260
340
|
### DynoQuery
|
|
@@ -266,29 +346,34 @@ if (token) {
|
|
|
266
346
|
- `scan(params)`: Low-level ScanCommand wrapper.
|
|
267
347
|
- `batchWrite(items)`: Batch persists multiple `Item` objects.
|
|
268
348
|
- `batchRead(items)`: Batch fetches multiple `Item` or `IndexQuery` objects.
|
|
349
|
+
- `transactWrite(items)`: Performs atomic write operations (Put/Delete) for up to 100 items.
|
|
350
|
+
- `transactRead(items)`: Performs atomic read operations (Get) for up to 100 items.
|
|
269
351
|
- `[ModelName](id, skValue?)`: Returns a `Partition` instance for the given ID. If `skValue` is provided, returns an `Item` object directly.
|
|
270
352
|
- `findBy[IndexName](id, skValue?)`: Returns an `IndexQuery` instance.
|
|
271
353
|
|
|
272
354
|
### Partition
|
|
273
355
|
- `get(skValue)`: Fetches data for a specific Sort Key value (returns a Promise).
|
|
274
|
-
- `getAll(options?)`: Fetches items in the partition. Options: `{ limit, exclusiveStartKey }`.
|
|
275
|
-
- `create(skValue, data, indices?)`: Creates an item. `
|
|
276
|
-
- `update(skValue, data)`: Partial update of an item.
|
|
277
|
-
- `delete(skValue)`: Deletes an item.
|
|
356
|
+
- `getAll(options?)`: Fetches items in the partition. Options: `{ limit, exclusiveStartKey, filterBuilder, FilterExpression, ExpressionAttributeNames, ExpressionAttributeValues }`.
|
|
357
|
+
- `create(skValue, data, indices?, options?)`: Creates an item. `options`: `{ conditionBuilder, ConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues }`.
|
|
358
|
+
- `update(skValue, data, indices?, options?)`: Partial update of an item. `options`: `{ conditionBuilder, ConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues }`.
|
|
359
|
+
- `delete(skValue, options?)`: Deletes an item. `options`: `{ conditionBuilder, ConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues }`.
|
|
278
360
|
- `draft(skValue, data?)`: Returns an `Item` object initialized with `data` (optional).
|
|
361
|
+
- `draftDelete(skValue)`: Returns an `Item` object marked for deletion (for use with `batchWrite`).
|
|
279
362
|
- `deleteAll()`: Deletes all items in the partition.
|
|
280
363
|
- `getLastEvaluatedKey()`: Returns the pagination token from the last `getAll()`.
|
|
281
364
|
|
|
282
365
|
### IndexQuery
|
|
283
366
|
- `get(skValue?)`: Get a single item from the index.
|
|
284
|
-
- `getAll(options?)`: Query index. Options: `{ limit, scanIndexForward, exclusiveStartKey, skValue }`.
|
|
367
|
+
- `getAll(options?)`: Query index. Options: `{ limit, scanIndexForward, exclusiveStartKey, skValue, filterBuilder, FilterExpression, ExpressionAttributeNames, ExpressionAttributeValues }`.
|
|
285
368
|
- `getLastEvaluatedKey()`: Returns the pagination token from the last `getAll()`.
|
|
286
369
|
|
|
287
370
|
### Item (returned by Partition.get or draft)
|
|
288
|
-
- `create(data?, indices?)`: Persists the item as a new record with the provided data. Supports GSI indices
|
|
289
|
-
- `update(data, indices?)`: Partial update of the item. Supports GSI indices
|
|
290
|
-
- `save()`: Persists the current state of the item
|
|
291
|
-
- `setIndex(indices)`: Attaches one or more `IndexQuery` objects to the item
|
|
371
|
+
- `create(data?, indices?)`: Persists the item as a new record with the provided data. Supports GSI indices and internal `conditionBuilder`.
|
|
372
|
+
- `update(data, indices?)`: Partial update of the item. Supports GSI indices and internal `conditionBuilder`.
|
|
373
|
+
- `save()`: Persists the current state of the item. Uses indices attached via `setIndex()` and internal `conditionBuilder`.
|
|
374
|
+
- `setIndex(indices)`: Attaches one or more `IndexQuery` objects to the item.
|
|
375
|
+
- `setFilter(builder)`: Sets a filter expression builder for the item.
|
|
376
|
+
- `setCondition(builder)`: Sets a condition for the item using an `ExpressionBuilder`.
|
|
292
377
|
|
|
293
378
|
## License
|
|
294
379
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export type Operand = string | number | ExpressionBuilder;
|
|
2
|
+
export declare class ExpressionBuilder {
|
|
3
|
+
private parts;
|
|
4
|
+
private attributeNames;
|
|
5
|
+
private attributeValues;
|
|
6
|
+
private valueCounter;
|
|
7
|
+
private nameCounter;
|
|
8
|
+
constructor();
|
|
9
|
+
static field(name: string): ExpressionBuilder;
|
|
10
|
+
static value(val: any): ExpressionBuilder;
|
|
11
|
+
where(field: string, operator: string, value: any): ExpressionBuilder;
|
|
12
|
+
equals(value: any): ExpressionBuilder;
|
|
13
|
+
notEquals(value: any): ExpressionBuilder;
|
|
14
|
+
lessThan(value: any): ExpressionBuilder;
|
|
15
|
+
lessThanOrEqual(value: any): ExpressionBuilder;
|
|
16
|
+
greaterThan(value: any): ExpressionBuilder;
|
|
17
|
+
greaterThanOrEqual(value: any): ExpressionBuilder;
|
|
18
|
+
between(start: any, end: any): ExpressionBuilder;
|
|
19
|
+
in(values: any[]): ExpressionBuilder;
|
|
20
|
+
exists(): ExpressionBuilder;
|
|
21
|
+
notExists(): ExpressionBuilder;
|
|
22
|
+
type(type: string): ExpressionBuilder;
|
|
23
|
+
attributeExists(path: string): ExpressionBuilder;
|
|
24
|
+
attributeNotExists(path: string): ExpressionBuilder;
|
|
25
|
+
attributeType(path: string, type: string): ExpressionBuilder;
|
|
26
|
+
beginsWith(pathOrSubstr: string, substr?: string): ExpressionBuilder;
|
|
27
|
+
contains(pathOrValue: string, value?: any): ExpressionBuilder;
|
|
28
|
+
size(path?: string): ExpressionBuilder;
|
|
29
|
+
and(other: ExpressionBuilder): ExpressionBuilder;
|
|
30
|
+
or(other: ExpressionBuilder): ExpressionBuilder;
|
|
31
|
+
static not(condition: ExpressionBuilder): ExpressionBuilder;
|
|
32
|
+
build(attributeNames?: Record<string, string>, attributeValues?: Record<string, any>, counters?: {
|
|
33
|
+
name: number;
|
|
34
|
+
value: number;
|
|
35
|
+
}): {
|
|
36
|
+
expression: string;
|
|
37
|
+
attributeNames: Record<string, string>;
|
|
38
|
+
attributeValues: Record<string, any>;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export declare function attr(name: string): ExpressionBuilder;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExpressionBuilder = void 0;
|
|
4
|
+
exports.attr = attr;
|
|
5
|
+
class ExpressionBuilder {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.parts = [];
|
|
8
|
+
this.attributeNames = {};
|
|
9
|
+
this.attributeValues = {};
|
|
10
|
+
this.valueCounter = 0;
|
|
11
|
+
this.nameCounter = 0;
|
|
12
|
+
}
|
|
13
|
+
static field(name) {
|
|
14
|
+
const builder = new ExpressionBuilder();
|
|
15
|
+
builder.parts.push({ type: 'field', name });
|
|
16
|
+
return builder;
|
|
17
|
+
}
|
|
18
|
+
static value(val) {
|
|
19
|
+
const builder = new ExpressionBuilder();
|
|
20
|
+
builder.parts.push({ type: 'value', value: val });
|
|
21
|
+
return builder;
|
|
22
|
+
}
|
|
23
|
+
where(field, operator, value) {
|
|
24
|
+
this.parts.push({ type: 'condition', field, operator, value });
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
equals(value) {
|
|
28
|
+
this.parts.push({ type: 'operator', operator: '=', value });
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
notEquals(value) {
|
|
32
|
+
this.parts.push({ type: 'operator', operator: '<>', value });
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
lessThan(value) {
|
|
36
|
+
this.parts.push({ type: 'operator', operator: '<', value });
|
|
37
|
+
return this;
|
|
38
|
+
}
|
|
39
|
+
lessThanOrEqual(value) {
|
|
40
|
+
this.parts.push({ type: 'operator', operator: '<=', value });
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
greaterThan(value) {
|
|
44
|
+
this.parts.push({ type: 'operator', operator: '>', value });
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
greaterThanOrEqual(value) {
|
|
48
|
+
this.parts.push({ type: 'operator', operator: '>=', value });
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
between(start, end) {
|
|
52
|
+
this.parts.push({ type: 'between', start, end });
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
in(values) {
|
|
56
|
+
this.parts.push({ type: 'in', values });
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
exists() {
|
|
60
|
+
const last = this.parts.pop();
|
|
61
|
+
if (last && last.type === 'field') {
|
|
62
|
+
this.parts.push({ type: 'function', name: 'attribute_exists', args: [last] });
|
|
63
|
+
}
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
notExists() {
|
|
67
|
+
const last = this.parts.pop();
|
|
68
|
+
if (last && last.type === 'field') {
|
|
69
|
+
this.parts.push({ type: 'function', name: 'attribute_not_exists', args: [last] });
|
|
70
|
+
}
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
type(type) {
|
|
74
|
+
const last = this.parts.pop();
|
|
75
|
+
if (last && last.type === 'field') {
|
|
76
|
+
this.parts.push({ type: 'function', name: 'attribute_type', args: [last, { type: 'value', value: type }] });
|
|
77
|
+
}
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
attributeExists(path) {
|
|
81
|
+
this.parts.push({ type: 'function', name: 'attribute_exists', args: [{ type: 'field', name: path }] });
|
|
82
|
+
return this;
|
|
83
|
+
}
|
|
84
|
+
attributeNotExists(path) {
|
|
85
|
+
this.parts.push({ type: 'function', name: 'attribute_not_exists', args: [{ type: 'field', name: path }] });
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
attributeType(path, type) {
|
|
89
|
+
this.parts.push({ type: 'function', name: 'attribute_type', args: [{ type: 'field', name: path }, { type: 'value', value: type }] });
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
beginsWith(pathOrSubstr, substr) {
|
|
93
|
+
if (substr !== undefined) {
|
|
94
|
+
// Legacy static-like call: builder.beginsWith('field', 'prefix')
|
|
95
|
+
this.parts.push({ type: 'function', name: 'begins_with', args: [{ type: 'field', name: pathOrSubstr }, { type: 'value', value: substr }] });
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// Fluent call: attr('field').beginsWith('prefix')
|
|
99
|
+
const last = this.parts.pop();
|
|
100
|
+
if (last && last.type === 'field') {
|
|
101
|
+
this.parts.push({ type: 'function', name: 'begins_with', args: [last, { type: 'value', value: pathOrSubstr }] });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return this;
|
|
105
|
+
}
|
|
106
|
+
contains(pathOrValue, value) {
|
|
107
|
+
if (value !== undefined) {
|
|
108
|
+
// Legacy static-like call: builder.contains('field', 'value')
|
|
109
|
+
this.parts.push({ type: 'function', name: 'contains', args: [{ type: 'field', name: pathOrValue }, { type: 'value', value }] });
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Fluent call: attr('field').contains('value')
|
|
113
|
+
const last = this.parts.pop();
|
|
114
|
+
if (last && last.type === 'field') {
|
|
115
|
+
this.parts.push({ type: 'function', name: 'contains', args: [last, { type: 'value', value: pathOrValue }] });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
size(path) {
|
|
121
|
+
if (path) {
|
|
122
|
+
// Legacy: builder.size('field')
|
|
123
|
+
const builder = new ExpressionBuilder();
|
|
124
|
+
builder.parts.push({ type: 'function', name: 'size', args: [{ type: 'field', name: path }] });
|
|
125
|
+
return builder;
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// Fluent: attr('field').size()
|
|
129
|
+
const last = this.parts.pop();
|
|
130
|
+
if (last && last.type === 'field') {
|
|
131
|
+
this.parts.push({ type: 'function', name: 'size', args: [last] });
|
|
132
|
+
}
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
and(other) {
|
|
137
|
+
const newBuilder = new ExpressionBuilder();
|
|
138
|
+
newBuilder.parts.push({ type: 'group', builder: this });
|
|
139
|
+
newBuilder.parts.push({ type: 'logical', operator: 'AND' });
|
|
140
|
+
newBuilder.parts.push({ type: 'group', builder: other });
|
|
141
|
+
return newBuilder;
|
|
142
|
+
}
|
|
143
|
+
or(other) {
|
|
144
|
+
const newBuilder = new ExpressionBuilder();
|
|
145
|
+
newBuilder.parts.push({ type: 'group', builder: this });
|
|
146
|
+
newBuilder.parts.push({ type: 'logical', operator: 'OR' });
|
|
147
|
+
newBuilder.parts.push({ type: 'group', builder: other });
|
|
148
|
+
return newBuilder;
|
|
149
|
+
}
|
|
150
|
+
static not(condition) {
|
|
151
|
+
const builder = new ExpressionBuilder();
|
|
152
|
+
builder.parts.push({ type: 'logical', operator: 'NOT' });
|
|
153
|
+
builder.parts.push({ type: 'group', builder: condition });
|
|
154
|
+
return builder;
|
|
155
|
+
}
|
|
156
|
+
build(attributeNames = {}, attributeValues = {}, counters = { name: 0, value: 0 }) {
|
|
157
|
+
let expressionParts = [];
|
|
158
|
+
for (const part of this.parts) {
|
|
159
|
+
switch (part.type) {
|
|
160
|
+
case 'field': {
|
|
161
|
+
const namePlaceholder = `#n${counters.name++}`;
|
|
162
|
+
attributeNames[namePlaceholder] = part.name;
|
|
163
|
+
expressionParts.push(namePlaceholder);
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
case 'value': {
|
|
167
|
+
const valuePlaceholder = `:v${counters.value++}`;
|
|
168
|
+
attributeValues[valuePlaceholder] = part.value;
|
|
169
|
+
expressionParts.push(valuePlaceholder);
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
case 'condition': {
|
|
173
|
+
const namePlaceholder = `#n${counters.name++}`;
|
|
174
|
+
attributeNames[namePlaceholder] = part.field;
|
|
175
|
+
const valuePlaceholder = `:v${counters.value++}`;
|
|
176
|
+
attributeValues[valuePlaceholder] = part.value;
|
|
177
|
+
expressionParts.push(`${namePlaceholder} ${part.operator} ${valuePlaceholder}`);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case 'operator': {
|
|
181
|
+
const valuePlaceholder = `:v${counters.value++}`;
|
|
182
|
+
attributeValues[valuePlaceholder] = part.value;
|
|
183
|
+
const last = expressionParts.pop();
|
|
184
|
+
expressionParts.push(`${last} ${part.operator} ${valuePlaceholder}`);
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case 'between': {
|
|
188
|
+
const startPlaceholder = `:v${counters.value++}`;
|
|
189
|
+
attributeValues[startPlaceholder] = part.start;
|
|
190
|
+
const endPlaceholder = `:v${counters.value++}`;
|
|
191
|
+
attributeValues[endPlaceholder] = part.end;
|
|
192
|
+
const last = expressionParts.pop();
|
|
193
|
+
expressionParts.push(`${last} BETWEEN ${startPlaceholder} AND ${endPlaceholder}`);
|
|
194
|
+
break;
|
|
195
|
+
}
|
|
196
|
+
case 'in': {
|
|
197
|
+
const placeholders = part.values.map((v) => {
|
|
198
|
+
const vp = `:v${counters.value++}`;
|
|
199
|
+
attributeValues[vp] = v;
|
|
200
|
+
return vp;
|
|
201
|
+
});
|
|
202
|
+
const last = expressionParts.pop();
|
|
203
|
+
expressionParts.push(`${last} IN (${placeholders.join(', ')})`);
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
206
|
+
case 'function': {
|
|
207
|
+
const args = part.args.map((arg) => {
|
|
208
|
+
if (arg.type === 'field') {
|
|
209
|
+
const np = `#n${counters.name++}`;
|
|
210
|
+
attributeNames[np] = arg.name;
|
|
211
|
+
return np;
|
|
212
|
+
}
|
|
213
|
+
else if (arg.type === 'value') {
|
|
214
|
+
const vp = `:v${counters.value++}`;
|
|
215
|
+
attributeValues[vp] = arg.value;
|
|
216
|
+
return vp;
|
|
217
|
+
}
|
|
218
|
+
else if (arg instanceof ExpressionBuilder) {
|
|
219
|
+
const sub = arg.build(attributeNames, attributeValues, counters);
|
|
220
|
+
return sub.expression;
|
|
221
|
+
}
|
|
222
|
+
return arg;
|
|
223
|
+
});
|
|
224
|
+
expressionParts.push(`${part.name}(${args.join(', ')})`);
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
case 'logical': {
|
|
228
|
+
expressionParts.push(part.operator);
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
case 'group': {
|
|
232
|
+
const sub = part.builder.build(attributeNames, attributeValues, counters);
|
|
233
|
+
expressionParts.push(`(${sub.expression})`);
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
expression: expressionParts.join(' '),
|
|
240
|
+
attributeNames,
|
|
241
|
+
attributeValues
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
exports.ExpressionBuilder = ExpressionBuilder;
|
|
246
|
+
function attr(name) {
|
|
247
|
+
return ExpressionBuilder.field(name);
|
|
248
|
+
}
|
package/dist/index-query.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DynoQuery } from "./index";
|
|
2
|
+
import { ExpressionBuilder } from "./expression-builder";
|
|
2
3
|
export interface IndexQueryConfig {
|
|
3
4
|
tableName?: string;
|
|
4
5
|
indexName: string;
|
|
@@ -23,9 +24,10 @@ export declare class IndexQuery {
|
|
|
23
24
|
scanIndexForward?: boolean;
|
|
24
25
|
exclusiveStartKey?: any;
|
|
25
26
|
skValue?: string;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
filterBuilder?: ExpressionBuilder;
|
|
28
|
+
FilterExpression?: string;
|
|
29
|
+
ExpressionAttributeNames?: Record<string, string>;
|
|
30
|
+
ExpressionAttributeValues?: Record<string, any>;
|
|
29
31
|
}): Promise<T[]>;
|
|
30
32
|
get<T = any>(skValue?: string): Promise<T | null>;
|
|
31
33
|
getPkValue(): string;
|
package/dist/index-query.js
CHANGED
|
@@ -34,18 +34,25 @@ class IndexQuery {
|
|
|
34
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
35
35
|
const finalSkValue = (options === null || options === void 0 ? void 0 : options.skValue) || this.skValue;
|
|
36
36
|
let keyCondition = "#pk = :pk";
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
let expressionAttributeNames = Object.assign({ "#pk": this.pkName }, options === null || options === void 0 ? void 0 : options.ExpressionAttributeNames);
|
|
38
|
+
let expressionAttributeValues = Object.assign({ ":pk": this.pkValue }, options === null || options === void 0 ? void 0 : options.ExpressionAttributeValues);
|
|
39
39
|
if (finalSkValue) {
|
|
40
40
|
keyCondition += " AND begins_with(#sk, :sk)";
|
|
41
41
|
expressionAttributeNames["#sk"] = this.skName;
|
|
42
42
|
expressionAttributeValues[":sk"] = finalSkValue;
|
|
43
43
|
}
|
|
44
|
+
let filterExpression = options === null || options === void 0 ? void 0 : options.FilterExpression;
|
|
45
|
+
if (options === null || options === void 0 ? void 0 : options.filterBuilder) {
|
|
46
|
+
const { expression, attributeNames, attributeValues } = options.filterBuilder.build();
|
|
47
|
+
filterExpression = expression;
|
|
48
|
+
expressionAttributeNames = Object.assign(Object.assign({}, expressionAttributeNames), attributeNames);
|
|
49
|
+
expressionAttributeValues = Object.assign(Object.assign({}, expressionAttributeValues), attributeValues);
|
|
50
|
+
}
|
|
44
51
|
const response = yield this.db.query({
|
|
45
52
|
TableName: this.tableName,
|
|
46
53
|
IndexName: this.indexName,
|
|
47
54
|
KeyConditionExpression: keyCondition,
|
|
48
|
-
FilterExpression:
|
|
55
|
+
FilterExpression: filterExpression,
|
|
49
56
|
ExpressionAttributeNames: expressionAttributeNames,
|
|
50
57
|
ExpressionAttributeValues: expressionAttributeValues,
|
|
51
58
|
Limit: options === null || options === void 0 ? void 0 : options.limit,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { PutCommandInput, GetCommandInput, UpdateCommandInput, DeleteCommandInput, QueryCommandInput, ScanCommandInput } from "@aws-sdk/lib-dynamodb";
|
|
2
2
|
import { Item } from "./partition";
|
|
3
3
|
import { IndexQuery } from "./index-query";
|
|
4
|
+
import { ExpressionBuilder, attr } from "./expression-builder";
|
|
5
|
+
export { ExpressionBuilder, attr };
|
|
4
6
|
export interface DynoQueryConfig {
|
|
5
7
|
tableName?: string;
|
|
6
8
|
pkName?: string;
|
|
@@ -65,6 +67,14 @@ export declare class DynoQuery {
|
|
|
65
67
|
* Batch get items from the table.
|
|
66
68
|
*/
|
|
67
69
|
batchRead(items: (Item | IndexQuery)[]): Promise<any[]>;
|
|
70
|
+
/**
|
|
71
|
+
* Transact write items to the table.
|
|
72
|
+
*/
|
|
73
|
+
transactWrite(items: Item[]): Promise<Item[]>;
|
|
74
|
+
/**
|
|
75
|
+
* Transact get items from the table.
|
|
76
|
+
*/
|
|
77
|
+
transactRead(items: (Item | IndexQuery)[]): Promise<any[]>;
|
|
68
78
|
/**
|
|
69
79
|
* Maps a raw DynamoDB item to a Model Item if it matches a registered model.
|
|
70
80
|
*/
|
package/dist/index.js
CHANGED
|
@@ -34,11 +34,14 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
34
34
|
return t;
|
|
35
35
|
};
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
exports.Item = exports.DynoQuery = void 0;
|
|
37
|
+
exports.Item = exports.DynoQuery = exports.attr = exports.ExpressionBuilder = void 0;
|
|
38
38
|
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
39
39
|
const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
|
|
40
40
|
const partition_1 = require("./partition");
|
|
41
41
|
const index_query_1 = require("./index-query");
|
|
42
|
+
const expression_builder_1 = require("./expression-builder");
|
|
43
|
+
Object.defineProperty(exports, "ExpressionBuilder", { enumerable: true, get: function () { return expression_builder_1.ExpressionBuilder; } });
|
|
44
|
+
Object.defineProperty(exports, "attr", { enumerable: true, get: function () { return expression_builder_1.attr; } });
|
|
42
45
|
class DynoQuery {
|
|
43
46
|
constructor(config = {}) {
|
|
44
47
|
this.registeredModels = {};
|
|
@@ -167,22 +170,41 @@ class DynoQuery {
|
|
|
167
170
|
if (!tableGroups[tableName]) {
|
|
168
171
|
tableGroups[tableName] = [];
|
|
169
172
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
173
|
+
if (item.toBeDeleted()) {
|
|
174
|
+
tableGroups[tableName].push({
|
|
175
|
+
DeleteRequest: {
|
|
176
|
+
Key: {
|
|
177
|
+
[this.pkName]: partition.getPkValue(),
|
|
178
|
+
[this.skName]: skValue,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const dataToSave = {};
|
|
185
|
+
for (const key in item) {
|
|
186
|
+
if (Object.prototype.hasOwnProperty.call(item, key) &&
|
|
187
|
+
![
|
|
188
|
+
"_indices",
|
|
189
|
+
"_partition",
|
|
190
|
+
"_skValue",
|
|
191
|
+
"_toBeDeleted",
|
|
192
|
+
"_filterBuilder",
|
|
193
|
+
"_conditionBuilder",
|
|
194
|
+
].includes(key) &&
|
|
195
|
+
typeof item[key] !== "function") {
|
|
196
|
+
dataToSave[key] = item[key];
|
|
197
|
+
}
|
|
176
198
|
}
|
|
199
|
+
// Ensure PK and SK are in the data
|
|
200
|
+
dataToSave[this.pkName] = partition.getPkValue();
|
|
201
|
+
dataToSave[this.skName] = skValue;
|
|
202
|
+
tableGroups[tableName].push({
|
|
203
|
+
PutRequest: {
|
|
204
|
+
Item: dataToSave,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
177
207
|
}
|
|
178
|
-
// Ensure PK and SK are in the data
|
|
179
|
-
dataToSave[this.pkName] = partition.getPkValue();
|
|
180
|
-
dataToSave[this.skName] = skValue;
|
|
181
|
-
tableGroups[tableName].push({
|
|
182
|
-
PutRequest: {
|
|
183
|
-
Item: dataToSave,
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
208
|
});
|
|
187
209
|
const results = [];
|
|
188
210
|
const tableNames = Object.keys(tableGroups);
|
|
@@ -259,6 +281,130 @@ class DynoQuery {
|
|
|
259
281
|
return allItems;
|
|
260
282
|
});
|
|
261
283
|
}
|
|
284
|
+
/**
|
|
285
|
+
* Transact write items to the table.
|
|
286
|
+
*/
|
|
287
|
+
transactWrite(items) {
|
|
288
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
289
|
+
// Chunk items into 100
|
|
290
|
+
for (let i = 0; i < items.length; i += 100) {
|
|
291
|
+
const chunk = items.slice(i, i + 100);
|
|
292
|
+
const transactItems = chunk.map((item) => {
|
|
293
|
+
const partition = item.getPartition();
|
|
294
|
+
const tableName = partition.getTableName();
|
|
295
|
+
const skValue = item.getSkValue();
|
|
296
|
+
const pkValue = partition.getPkValue();
|
|
297
|
+
const conditionBuilder = item.getConditionBuilder();
|
|
298
|
+
if (item.toBeDeleted()) {
|
|
299
|
+
const deleteItem = {
|
|
300
|
+
Key: {
|
|
301
|
+
[this.pkName]: pkValue,
|
|
302
|
+
[this.skName]: skValue,
|
|
303
|
+
},
|
|
304
|
+
TableName: tableName,
|
|
305
|
+
};
|
|
306
|
+
if (conditionBuilder) {
|
|
307
|
+
const { expression, attributeNames, attributeValues } = conditionBuilder.build();
|
|
308
|
+
deleteItem.ConditionExpression = expression;
|
|
309
|
+
deleteItem.ExpressionAttributeNames = attributeNames;
|
|
310
|
+
deleteItem.ExpressionAttributeValues = attributeValues;
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
Delete: deleteItem,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
const dataToSave = {};
|
|
318
|
+
for (const key in item) {
|
|
319
|
+
if (Object.prototype.hasOwnProperty.call(item, key) &&
|
|
320
|
+
![
|
|
321
|
+
"_indices",
|
|
322
|
+
"_partition",
|
|
323
|
+
"_skValue",
|
|
324
|
+
"_toBeDeleted",
|
|
325
|
+
"_filterBuilder",
|
|
326
|
+
"_conditionBuilder",
|
|
327
|
+
].includes(key) &&
|
|
328
|
+
typeof item[key] !== "function") {
|
|
329
|
+
dataToSave[key] = item[key];
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// Ensure PK and SK are in the data
|
|
333
|
+
dataToSave[this.pkName] = pkValue;
|
|
334
|
+
dataToSave[this.skName] = skValue;
|
|
335
|
+
const putItem = {
|
|
336
|
+
Item: dataToSave,
|
|
337
|
+
TableName: tableName,
|
|
338
|
+
};
|
|
339
|
+
if (conditionBuilder) {
|
|
340
|
+
const { expression, attributeNames, attributeValues } = conditionBuilder.build();
|
|
341
|
+
putItem.ConditionExpression = expression;
|
|
342
|
+
putItem.ExpressionAttributeNames = attributeNames;
|
|
343
|
+
putItem.ExpressionAttributeValues = attributeValues;
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
Put: putItem,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
yield this.docClient.send(new lib_dynamodb_1.TransactWriteCommand({
|
|
351
|
+
TransactItems: transactItems,
|
|
352
|
+
}));
|
|
353
|
+
}
|
|
354
|
+
return items;
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Transact get items from the table.
|
|
359
|
+
*/
|
|
360
|
+
transactRead(items) {
|
|
361
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
362
|
+
const allItems = [];
|
|
363
|
+
// Chunk items into 100
|
|
364
|
+
for (let i = 0; i < items.length; i += 100) {
|
|
365
|
+
const chunk = items.slice(i, i + 100);
|
|
366
|
+
const transactItems = chunk.map((item) => {
|
|
367
|
+
let tableName;
|
|
368
|
+
let pkValue;
|
|
369
|
+
let skValue;
|
|
370
|
+
if (item instanceof index_query_1.IndexQuery) {
|
|
371
|
+
tableName = item.tableName;
|
|
372
|
+
pkValue = item.getPkValue();
|
|
373
|
+
skValue = item.getSkValue() || "";
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
const partition = item.getPartition();
|
|
377
|
+
tableName = partition.getTableName();
|
|
378
|
+
pkValue = partition.getPkValue();
|
|
379
|
+
skValue = item.getSkValue();
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
Get: {
|
|
383
|
+
TableName: tableName,
|
|
384
|
+
Key: {
|
|
385
|
+
[this.pkName]: pkValue,
|
|
386
|
+
[this.skName]: skValue,
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
});
|
|
391
|
+
const response = yield this.docClient.send(new lib_dynamodb_1.TransactGetCommand({
|
|
392
|
+
TransactItems: transactItems,
|
|
393
|
+
}));
|
|
394
|
+
if (response.Responses) {
|
|
395
|
+
response.Responses.forEach((res) => {
|
|
396
|
+
if (res.Item) {
|
|
397
|
+
allItems.push(this.mapItemToModelItem(res.Item));
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
allItems.push(null);
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
return allItems;
|
|
406
|
+
});
|
|
407
|
+
}
|
|
262
408
|
/**
|
|
263
409
|
* Maps a raw DynamoDB item to a Model Item if it matches a registered model.
|
|
264
410
|
*/
|
package/dist/partition.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DynoQuery } from "./index";
|
|
2
2
|
import { IndexQuery } from "./index-query";
|
|
3
|
+
import { ExpressionBuilder } from "./expression-builder";
|
|
3
4
|
export interface PartitionConfig {
|
|
4
5
|
tableName?: string;
|
|
5
6
|
pk?: string;
|
|
@@ -10,6 +11,9 @@ export declare class Item {
|
|
|
10
11
|
private _indices;
|
|
11
12
|
private _partition;
|
|
12
13
|
private _skValue;
|
|
14
|
+
private _toBeDeleted;
|
|
15
|
+
private _filterBuilder?;
|
|
16
|
+
private _conditionBuilder?;
|
|
13
17
|
constructor(partition: Partition, skValue: string, data: any);
|
|
14
18
|
}
|
|
15
19
|
export declare class Partition {
|
|
@@ -29,14 +33,20 @@ export declare class Partition {
|
|
|
29
33
|
getAll<T = any>(options?: {
|
|
30
34
|
limit?: number;
|
|
31
35
|
exclusiveStartKey?: any;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
filterBuilder?: ExpressionBuilder;
|
|
37
|
+
FilterExpression?: string;
|
|
38
|
+
ExpressionAttributeNames?: Record<string, string>;
|
|
39
|
+
ExpressionAttributeValues?: Record<string, any>;
|
|
35
40
|
}): Promise<T[]>;
|
|
36
41
|
/**
|
|
37
42
|
* Create an item in this partition.
|
|
38
43
|
*/
|
|
39
|
-
create<T = any>(skValue: string, data: T, indices?: IndexQuery[]
|
|
44
|
+
create<T = any>(skValue: string, data: T, indices?: IndexQuery[], options?: {
|
|
45
|
+
conditionBuilder?: ExpressionBuilder;
|
|
46
|
+
ConditionExpression?: string;
|
|
47
|
+
ExpressionAttributeNames?: Record<string, string>;
|
|
48
|
+
ExpressionAttributeValues?: Record<string, any>;
|
|
49
|
+
}): Promise<T>;
|
|
40
50
|
/**
|
|
41
51
|
* Internal method to get raw data for a specific SK.
|
|
42
52
|
*/
|
|
@@ -44,21 +54,36 @@ export declare class Partition {
|
|
|
44
54
|
/**
|
|
45
55
|
* Update an existing item in this partition.
|
|
46
56
|
*/
|
|
47
|
-
update<T = any>(skValue: string, data: Partial<T>, indices?: IndexQuery[]
|
|
57
|
+
update<T = any>(skValue: string, data: Partial<T>, indices?: IndexQuery[], options?: {
|
|
58
|
+
conditionBuilder?: ExpressionBuilder;
|
|
59
|
+
ConditionExpression?: string;
|
|
60
|
+
ExpressionAttributeNames?: Record<string, string>;
|
|
61
|
+
ExpressionAttributeValues?: Record<string, any>;
|
|
62
|
+
}): Promise<T>;
|
|
48
63
|
/**
|
|
49
64
|
* Delete an item by its SK within this partition.
|
|
50
65
|
*/
|
|
51
|
-
delete(skValue: string
|
|
66
|
+
delete(skValue: string, options?: {
|
|
67
|
+
conditionBuilder?: ExpressionBuilder;
|
|
68
|
+
ConditionExpression?: string;
|
|
69
|
+
ExpressionAttributeNames?: Record<string, string>;
|
|
70
|
+
ExpressionAttributeValues?: Record<string, any>;
|
|
71
|
+
}): Promise<void>;
|
|
52
72
|
/**
|
|
53
73
|
* Get data for a specific SK and return it wrapped in a Item object.
|
|
54
74
|
*/
|
|
55
75
|
get<T = any>(skValue: string): Promise<T | null>;
|
|
56
76
|
/**
|
|
57
77
|
* Pre-draft an item for creation. Returns an Item object.
|
|
58
|
-
* @param
|
|
78
|
+
* @param skValue The sort key value
|
|
59
79
|
* @param data Initial data for the row
|
|
60
80
|
*/
|
|
61
81
|
draft<T = any>(skValue: string, data?: any): T;
|
|
82
|
+
/**
|
|
83
|
+
* Pre-draft an item for deletion. Returns an Item object marked for deletion.
|
|
84
|
+
* @param skValue The sort key value
|
|
85
|
+
*/
|
|
86
|
+
draftDelete<T = any>(skValue: string): T;
|
|
62
87
|
getTableName(): string;
|
|
63
88
|
getPkValue(): string;
|
|
64
89
|
getLastEvaluatedKey(): any;
|
package/dist/partition.js
CHANGED
|
@@ -15,6 +15,7 @@ class Item {
|
|
|
15
15
|
this._indices = [];
|
|
16
16
|
this._partition = partition;
|
|
17
17
|
this._skValue = skValue;
|
|
18
|
+
this._toBeDeleted = !!(data === null || data === void 0 ? void 0 : data._toBeDeleted);
|
|
18
19
|
Object.assign(this, data);
|
|
19
20
|
const self = this;
|
|
20
21
|
return new Proxy(this, {
|
|
@@ -24,26 +25,50 @@ class Item {
|
|
|
24
25
|
const dataToSave = {};
|
|
25
26
|
for (const key in target) {
|
|
26
27
|
if (Object.prototype.hasOwnProperty.call(target, key) &&
|
|
27
|
-
!["_indices", "_partition", "_skValue"].includes(key) &&
|
|
28
|
+
!["_indices", "_partition", "_skValue", "_toBeDeleted", "_filterBuilder", "_conditionBuilder"].includes(key) &&
|
|
28
29
|
typeof target[key] !== "function") {
|
|
29
30
|
dataToSave[key] = target[key];
|
|
30
31
|
}
|
|
31
32
|
}
|
|
32
|
-
return partition.update(skValue, dataToSave, self._indices
|
|
33
|
+
return partition.update(skValue, dataToSave, self._indices, {
|
|
34
|
+
conditionBuilder: self._conditionBuilder,
|
|
35
|
+
});
|
|
33
36
|
};
|
|
34
37
|
}
|
|
35
38
|
if (prop === "create") {
|
|
36
39
|
return (data, indices) => {
|
|
37
40
|
const dataToSave = data || {};
|
|
38
41
|
const finalIndices = indices || self._indices;
|
|
39
|
-
return partition.create(skValue, dataToSave, finalIndices
|
|
42
|
+
return partition.create(skValue, dataToSave, finalIndices, {
|
|
43
|
+
conditionBuilder: self._conditionBuilder,
|
|
44
|
+
});
|
|
40
45
|
};
|
|
41
46
|
}
|
|
42
47
|
if (prop === "update") {
|
|
43
48
|
return (data, indices) => {
|
|
44
|
-
return partition.update(skValue, data, indices
|
|
49
|
+
return partition.update(skValue, data, indices, {
|
|
50
|
+
conditionBuilder: self._conditionBuilder,
|
|
51
|
+
});
|
|
45
52
|
};
|
|
46
53
|
}
|
|
54
|
+
if (prop === "setFilter") {
|
|
55
|
+
return (builder) => {
|
|
56
|
+
self._filterBuilder = builder;
|
|
57
|
+
return receiver;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (prop === "setCondition") {
|
|
61
|
+
return (builder) => {
|
|
62
|
+
self._conditionBuilder = builder;
|
|
63
|
+
return receiver;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (prop === "getFilterBuilder") {
|
|
67
|
+
return () => self._filterBuilder;
|
|
68
|
+
}
|
|
69
|
+
if (prop === "getConditionBuilder") {
|
|
70
|
+
return () => self._conditionBuilder;
|
|
71
|
+
}
|
|
47
72
|
if (prop === "setIndex") {
|
|
48
73
|
return (indexObj) => {
|
|
49
74
|
if (Array.isArray(indexObj)) {
|
|
@@ -61,6 +86,9 @@ class Item {
|
|
|
61
86
|
if (prop === "getSkValue") {
|
|
62
87
|
return () => skValue;
|
|
63
88
|
}
|
|
89
|
+
if (prop === "toBeDeleted") {
|
|
90
|
+
return () => self._toBeDeleted;
|
|
91
|
+
}
|
|
64
92
|
return Reflect.get(target, prop, receiver);
|
|
65
93
|
},
|
|
66
94
|
});
|
|
@@ -114,12 +142,21 @@ class Partition {
|
|
|
114
142
|
*/
|
|
115
143
|
getAll(options) {
|
|
116
144
|
return __awaiter(this, void 0, void 0, function* () {
|
|
145
|
+
let filterExpression = options === null || options === void 0 ? void 0 : options.FilterExpression;
|
|
146
|
+
let expressionAttributeNames = Object.assign({ "#pk": this.pkName }, options === null || options === void 0 ? void 0 : options.ExpressionAttributeNames);
|
|
147
|
+
let expressionAttributeValues = Object.assign({ ":pk": this.pkValue }, options === null || options === void 0 ? void 0 : options.ExpressionAttributeValues);
|
|
148
|
+
if (options === null || options === void 0 ? void 0 : options.filterBuilder) {
|
|
149
|
+
const { expression, attributeNames, attributeValues } = options.filterBuilder.build();
|
|
150
|
+
filterExpression = expression;
|
|
151
|
+
expressionAttributeNames = Object.assign(Object.assign({}, expressionAttributeNames), attributeNames);
|
|
152
|
+
expressionAttributeValues = Object.assign(Object.assign({}, expressionAttributeValues), attributeValues);
|
|
153
|
+
}
|
|
117
154
|
const response = yield this.db.query({
|
|
118
155
|
TableName: this.tableName,
|
|
119
156
|
KeyConditionExpression: "#pk = :pk",
|
|
120
|
-
FilterExpression:
|
|
121
|
-
ExpressionAttributeNames:
|
|
122
|
-
ExpressionAttributeValues:
|
|
157
|
+
FilterExpression: filterExpression,
|
|
158
|
+
ExpressionAttributeNames: expressionAttributeNames,
|
|
159
|
+
ExpressionAttributeValues: expressionAttributeValues,
|
|
123
160
|
Limit: options === null || options === void 0 ? void 0 : options.limit,
|
|
124
161
|
ExclusiveStartKey: options === null || options === void 0 ? void 0 : options.exclusiveStartKey,
|
|
125
162
|
});
|
|
@@ -139,7 +176,7 @@ class Partition {
|
|
|
139
176
|
/**
|
|
140
177
|
* Create an item in this partition.
|
|
141
178
|
*/
|
|
142
|
-
create(skValue, data, indices) {
|
|
179
|
+
create(skValue, data, indices, options) {
|
|
143
180
|
return __awaiter(this, void 0, void 0, function* () {
|
|
144
181
|
const item = Object.assign({ [this.pkName]: this.pkValue, [this.skName]: skValue }, data);
|
|
145
182
|
if (indices) {
|
|
@@ -150,10 +187,22 @@ class Partition {
|
|
|
150
187
|
}
|
|
151
188
|
});
|
|
152
189
|
}
|
|
153
|
-
|
|
190
|
+
const createParams = {
|
|
154
191
|
TableName: this.tableName,
|
|
155
192
|
Item: item,
|
|
156
|
-
}
|
|
193
|
+
};
|
|
194
|
+
if (options === null || options === void 0 ? void 0 : options.conditionBuilder) {
|
|
195
|
+
const { expression, attributeNames, attributeValues } = options.conditionBuilder.build();
|
|
196
|
+
createParams.ConditionExpression = expression;
|
|
197
|
+
createParams.ExpressionAttributeNames = Object.assign(Object.assign({}, createParams.ExpressionAttributeNames), attributeNames);
|
|
198
|
+
createParams.ExpressionAttributeValues = Object.assign(Object.assign({}, createParams.ExpressionAttributeValues), attributeValues);
|
|
199
|
+
}
|
|
200
|
+
if (options === null || options === void 0 ? void 0 : options.ConditionExpression) {
|
|
201
|
+
createParams.ConditionExpression = options.ConditionExpression;
|
|
202
|
+
createParams.ExpressionAttributeNames = Object.assign(Object.assign({}, createParams.ExpressionAttributeNames), options.ExpressionAttributeNames);
|
|
203
|
+
createParams.ExpressionAttributeValues = Object.assign(Object.assign({}, createParams.ExpressionAttributeValues), options.ExpressionAttributeValues);
|
|
204
|
+
}
|
|
205
|
+
yield this.db.create(createParams);
|
|
157
206
|
this.cache[skValue] = item;
|
|
158
207
|
return new Item(this, skValue, item);
|
|
159
208
|
});
|
|
@@ -186,25 +235,37 @@ class Partition {
|
|
|
186
235
|
/**
|
|
187
236
|
* Update an existing item in this partition.
|
|
188
237
|
*/
|
|
189
|
-
update(skValue, data, indices) {
|
|
238
|
+
update(skValue, data, indices, options) {
|
|
190
239
|
return __awaiter(this, void 0, void 0, function* () {
|
|
191
240
|
const current = (yield this._getRaw(skValue)) || {};
|
|
192
241
|
const updated = Object.assign(Object.assign({}, current), data);
|
|
193
|
-
return yield this.create(skValue, updated, indices);
|
|
242
|
+
return yield this.create(skValue, updated, indices, options);
|
|
194
243
|
});
|
|
195
244
|
}
|
|
196
245
|
/**
|
|
197
246
|
* Delete an item by its SK within this partition.
|
|
198
247
|
*/
|
|
199
|
-
delete(skValue) {
|
|
248
|
+
delete(skValue, options) {
|
|
200
249
|
return __awaiter(this, void 0, void 0, function* () {
|
|
201
|
-
|
|
250
|
+
const deleteParams = {
|
|
202
251
|
TableName: this.tableName,
|
|
203
252
|
Key: {
|
|
204
253
|
[this.pkName]: this.pkValue,
|
|
205
254
|
[this.skName]: skValue,
|
|
206
255
|
},
|
|
207
|
-
}
|
|
256
|
+
};
|
|
257
|
+
if (options === null || options === void 0 ? void 0 : options.conditionBuilder) {
|
|
258
|
+
const { expression, attributeNames, attributeValues } = options.conditionBuilder.build();
|
|
259
|
+
deleteParams.ConditionExpression = expression;
|
|
260
|
+
deleteParams.ExpressionAttributeNames = Object.assign(Object.assign({}, deleteParams.ExpressionAttributeNames), attributeNames);
|
|
261
|
+
deleteParams.ExpressionAttributeValues = Object.assign(Object.assign({}, deleteParams.ExpressionAttributeValues), attributeValues);
|
|
262
|
+
}
|
|
263
|
+
if (options === null || options === void 0 ? void 0 : options.ConditionExpression) {
|
|
264
|
+
deleteParams.ConditionExpression = options.ConditionExpression;
|
|
265
|
+
deleteParams.ExpressionAttributeNames = Object.assign(Object.assign({}, deleteParams.ExpressionAttributeNames), options.ExpressionAttributeNames);
|
|
266
|
+
deleteParams.ExpressionAttributeValues = Object.assign(Object.assign({}, deleteParams.ExpressionAttributeValues), options.ExpressionAttributeValues);
|
|
267
|
+
}
|
|
268
|
+
yield this.db.delete(deleteParams);
|
|
208
269
|
delete this.cache[skValue];
|
|
209
270
|
});
|
|
210
271
|
}
|
|
@@ -219,12 +280,19 @@ class Partition {
|
|
|
219
280
|
}
|
|
220
281
|
/**
|
|
221
282
|
* Pre-draft an item for creation. Returns an Item object.
|
|
222
|
-
* @param
|
|
283
|
+
* @param skValue The sort key value
|
|
223
284
|
* @param data Initial data for the row
|
|
224
285
|
*/
|
|
225
286
|
draft(skValue, data = {}) {
|
|
226
287
|
return new Item(this, skValue, data);
|
|
227
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* Pre-draft an item for deletion. Returns an Item object marked for deletion.
|
|
291
|
+
* @param skValue The sort key value
|
|
292
|
+
*/
|
|
293
|
+
draftDelete(skValue) {
|
|
294
|
+
return new Item(this, skValue, { _toBeDeleted: true });
|
|
295
|
+
}
|
|
228
296
|
getTableName() {
|
|
229
297
|
return this.tableName || "";
|
|
230
298
|
}
|