betterddb 0.4.1 → 0.4.3
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/lib/betterddb.d.ts +102 -37
- package/lib/betterddb.js +72 -12
- package/lib/builders/create-builder.d.ts +9 -10
- package/lib/builders/create-builder.js +5 -4
- package/lib/builders/delete-builder.d.ts +5 -6
- package/lib/builders/delete-builder.js +4 -3
- package/lib/builders/get-builder.d.ts +10 -11
- package/lib/builders/get-builder.js +4 -3
- package/lib/builders/query-builder.d.ts +7 -8
- package/lib/builders/query-builder.js +2 -1
- package/lib/builders/scan-builder.d.ts +7 -8
- package/lib/builders/scan-builder.js +2 -1
- package/lib/builders/update-builder.d.ts +10 -11
- package/lib/builders/update-builder.js +4 -3
- package/package.json +3 -2
- package/src/betterddb.ts +163 -77
- package/src/builders/create-builder.ts +24 -23
- package/src/builders/delete-builder.ts +12 -13
- package/src/builders/get-builder.ts +19 -20
- package/src/builders/query-builder.ts +12 -13
- package/src/builders/scan-builder.ts +12 -13
- package/src/builders/update-builder.ts +25 -25
- package/test/create.test.ts +12 -8
- package/test/delete.test.ts +10 -7
- package/test/get.test.ts +10 -7
- package/test/query.test.ts +9 -6
- package/test/scan.test.ts +11 -7
- package/test/update.test.ts +10 -7
- package/test/utils/table-setup.ts +7 -7
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.UpdateBuilder = void 0;
|
|
4
|
+
const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
|
|
4
5
|
class UpdateBuilder {
|
|
5
6
|
// Reference to the parent BetterDDB instance and key.
|
|
6
7
|
constructor(parent, key, expectedVersion) {
|
|
@@ -170,9 +171,9 @@ class UpdateBuilder {
|
|
|
170
171
|
const myTransactItem = this.toTransactUpdate();
|
|
171
172
|
// Combine with extra transaction items.
|
|
172
173
|
const allItems = [...this.extraTransactItems, myTransactItem];
|
|
173
|
-
await this.parent.getClient().
|
|
174
|
+
await this.parent.getClient().send(new lib_dynamodb_1.TransactWriteCommand({
|
|
174
175
|
TransactItems: allItems
|
|
175
|
-
})
|
|
176
|
+
}));
|
|
176
177
|
// After transaction, retrieve the updated item.
|
|
177
178
|
const result = await this.parent.get(this.key).execute();
|
|
178
179
|
if (result === null) {
|
|
@@ -194,7 +195,7 @@ class UpdateBuilder {
|
|
|
194
195
|
if (this.condition && this.condition.expression) {
|
|
195
196
|
params.ConditionExpression = this.condition.expression;
|
|
196
197
|
}
|
|
197
|
-
const result = await this.parent.getClient().
|
|
198
|
+
const result = await this.parent.getClient().send(new lib_dynamodb_1.UpdateCommand(params));
|
|
198
199
|
if (!result.Attributes) {
|
|
199
200
|
throw new Error('No attributes returned after update');
|
|
200
201
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "betterddb",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "A definition-based DynamoDB wrapper library that provides a schema-driven and fully typesafe DAL.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"author": "R.R. Wang",
|
|
29
29
|
"license": "MIT",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"aws-sdk": "^
|
|
31
|
+
"@aws-sdk/lib-dynamodb": "^3.744.0",
|
|
32
|
+
"@aws-sdk/client-dynamodb": "^3.744.0",
|
|
32
33
|
"zod": "^3.21.4"
|
|
33
34
|
},
|
|
34
35
|
"devDependencies": {
|
package/src/betterddb.ts
CHANGED
|
@@ -1,85 +1,123 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { DynamoDB } from 'aws-sdk';
|
|
1
|
+
import { z, ZodSchema } from 'zod';
|
|
3
2
|
import { QueryBuilder } from './builders/query-builder';
|
|
4
3
|
import { ScanBuilder } from './builders/scan-builder';
|
|
5
4
|
import { UpdateBuilder } from './builders/update-builder';
|
|
6
5
|
import { CreateBuilder } from './builders/create-builder';
|
|
7
6
|
import { GetBuilder } from './builders/get-builder';
|
|
8
7
|
import { DeleteBuilder } from './builders/delete-builder';
|
|
9
|
-
|
|
10
|
-
export type SchemaType<S extends z.ZodType<any>> = z.infer<S>;
|
|
8
|
+
import { DynamoDBDocumentClient } from '@aws-sdk/lib-dynamodb';
|
|
11
9
|
|
|
12
10
|
export type PrimaryKeyValue = string | number;
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
/**
|
|
13
|
+
* A key definition can be either a simple key (a property name)
|
|
14
|
+
* or an object containing a build function that computes the value.
|
|
15
|
+
* (In this design, the attribute name is provided separately.)
|
|
16
|
+
*/
|
|
17
|
+
export type KeyDefinition<T> =
|
|
18
|
+
| keyof T
|
|
16
19
|
| {
|
|
17
|
-
build: (rawKey: Partial<
|
|
20
|
+
build: (rawKey: Partial<T>) => string;
|
|
18
21
|
};
|
|
19
22
|
|
|
20
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Configuration for a primary (partition) key.
|
|
25
|
+
*/
|
|
26
|
+
export interface PrimaryKeyConfig<T> {
|
|
27
|
+
/** The attribute name for the primary key in DynamoDB */
|
|
21
28
|
name: string;
|
|
22
|
-
|
|
29
|
+
/** How to compute the key value; if a keyof T, then the raw value is used;
|
|
30
|
+
* if an object, the build function is used.
|
|
31
|
+
*/
|
|
32
|
+
definition: KeyDefinition<T>;
|
|
23
33
|
}
|
|
24
34
|
|
|
25
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Configuration for a sort key.
|
|
37
|
+
*/
|
|
38
|
+
export interface SortKeyConfig<T> {
|
|
39
|
+
/** The attribute name for the sort key in DynamoDB */
|
|
26
40
|
name: string;
|
|
27
|
-
|
|
41
|
+
/** How to compute the sort key value */
|
|
42
|
+
definition: KeyDefinition<T>;
|
|
28
43
|
}
|
|
29
44
|
|
|
30
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Configuration for a Global Secondary Index (GSI).
|
|
47
|
+
*/
|
|
48
|
+
export interface GSIConfig<T> {
|
|
49
|
+
/** The name of the GSI in DynamoDB */
|
|
31
50
|
name: string;
|
|
32
|
-
primary
|
|
33
|
-
|
|
51
|
+
/** The primary key configuration for the GSI */
|
|
52
|
+
primary: PrimaryKeyConfig<T>;
|
|
53
|
+
/** The sort key configuration for the GSI, if any */
|
|
54
|
+
sort?: SortKeyConfig<T>;
|
|
34
55
|
}
|
|
35
56
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
57
|
+
/**
|
|
58
|
+
* Keys configuration for the table.
|
|
59
|
+
*/
|
|
60
|
+
export interface KeysConfig<T> {
|
|
61
|
+
primary: PrimaryKeyConfig<T>;
|
|
62
|
+
sort?: SortKeyConfig<T>;
|
|
39
63
|
gsis?: {
|
|
40
|
-
[gsiName: string]: GSIConfig<
|
|
64
|
+
[gsiName: string]: GSIConfig<T>;
|
|
41
65
|
};
|
|
42
66
|
}
|
|
43
67
|
|
|
44
|
-
|
|
45
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Options for initializing BetterDDB.
|
|
70
|
+
*/
|
|
71
|
+
export interface BetterDDBOptions<T> {
|
|
72
|
+
schema: ZodSchema;
|
|
46
73
|
tableName: string;
|
|
47
74
|
entityName: string;
|
|
48
|
-
keys: KeysConfig<
|
|
49
|
-
client:
|
|
75
|
+
keys: KeysConfig<T>;
|
|
76
|
+
client: DynamoDBDocumentClient;
|
|
77
|
+
/**
|
|
78
|
+
* If true, automatically inject timestamp fields:
|
|
79
|
+
* - On create, sets both `createdAt` and `updatedAt`
|
|
80
|
+
* - On update, sets `updatedAt`
|
|
81
|
+
*
|
|
82
|
+
* (T should include these fields if enabled.)
|
|
83
|
+
*/
|
|
50
84
|
autoTimestamps?: boolean;
|
|
51
85
|
}
|
|
52
86
|
|
|
53
|
-
|
|
54
|
-
|
|
87
|
+
/**
|
|
88
|
+
* BetterDDB is a definition-based DynamoDB wrapper library.
|
|
89
|
+
*/
|
|
90
|
+
export class BetterDDB<T> {
|
|
91
|
+
protected schema: ZodSchema;
|
|
55
92
|
protected tableName: string;
|
|
56
93
|
protected entityName: string;
|
|
57
|
-
protected client:
|
|
58
|
-
protected keys: KeysConfig<
|
|
94
|
+
protected client: DynamoDBDocumentClient;
|
|
95
|
+
protected keys: KeysConfig<T>;
|
|
59
96
|
protected autoTimestamps: boolean;
|
|
60
97
|
|
|
61
|
-
constructor(options: BetterDDBOptions<
|
|
98
|
+
constructor(options: BetterDDBOptions<T>) {
|
|
62
99
|
this.schema = options.schema;
|
|
63
100
|
this.tableName = options.tableName;
|
|
64
101
|
this.entityName = options.entityName.toUpperCase();
|
|
102
|
+
this.keys = options.keys;
|
|
65
103
|
this.client = options.client;
|
|
66
104
|
this.autoTimestamps = options.autoTimestamps ?? false;
|
|
67
|
-
this.keys = options.keys;
|
|
68
105
|
}
|
|
69
106
|
|
|
70
|
-
public getKeys(): KeysConfig<
|
|
107
|
+
public getKeys(): KeysConfig<T> {
|
|
71
108
|
return this.keys;
|
|
72
109
|
}
|
|
73
|
-
|
|
110
|
+
|
|
74
111
|
public getTableName(): string {
|
|
75
112
|
return this.tableName;
|
|
76
113
|
}
|
|
77
|
-
|
|
78
|
-
public getClient():
|
|
114
|
+
|
|
115
|
+
public getClient(): DynamoDBDocumentClient {
|
|
79
116
|
return this.client;
|
|
80
117
|
}
|
|
81
|
-
|
|
82
|
-
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
public getSchema(): ZodSchema {
|
|
83
121
|
return this.schema;
|
|
84
122
|
}
|
|
85
123
|
|
|
@@ -87,70 +125,118 @@ export class BetterDDB<S extends z.ZodType<any>> {
|
|
|
87
125
|
return this.autoTimestamps;
|
|
88
126
|
}
|
|
89
127
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
rawKey: Partial<SchemaType<S>>
|
|
93
|
-
): string {
|
|
128
|
+
// Helper: Retrieve the key value from a KeyDefinition.
|
|
129
|
+
protected getKeyValue(def: KeyDefinition<T>, rawKey: Partial<T>): string {
|
|
94
130
|
if (typeof def === 'string' || typeof def === 'number' || typeof def === 'symbol') {
|
|
95
|
-
return String(rawKey[def
|
|
131
|
+
return String(rawKey[def]);
|
|
132
|
+
} else {
|
|
133
|
+
return def.build(rawKey);
|
|
96
134
|
}
|
|
97
|
-
return def.build(rawKey);
|
|
98
135
|
}
|
|
99
136
|
|
|
100
|
-
|
|
137
|
+
/**
|
|
138
|
+
* Build the primary key from a raw key object.
|
|
139
|
+
*/
|
|
140
|
+
public buildKey(rawKey: Partial<T>): Record<string, any> {
|
|
101
141
|
const keyObj: Record<string, any> = {};
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
142
|
+
|
|
143
|
+
// For primary (partition) key:
|
|
144
|
+
const pkConfig = this.keys.primary;
|
|
145
|
+
keyObj[pkConfig.name] =
|
|
146
|
+
(typeof pkConfig.definition === 'string' ||
|
|
147
|
+
typeof pkConfig.definition === 'number' ||
|
|
148
|
+
typeof pkConfig.definition === 'symbol')
|
|
149
|
+
? String((rawKey as any)[pkConfig.definition])
|
|
150
|
+
: pkConfig.definition.build(rawKey);
|
|
151
|
+
|
|
152
|
+
// For sort key, if defined:
|
|
153
|
+
if (this.keys.sort) {
|
|
154
|
+
const skConfig = this.keys.sort;
|
|
155
|
+
keyObj[skConfig.name] =
|
|
156
|
+
(typeof skConfig.definition === 'string' ||
|
|
157
|
+
typeof skConfig.definition === 'number' ||
|
|
158
|
+
typeof skConfig.definition === 'symbol')
|
|
159
|
+
? String((rawKey as any)[skConfig.definition])
|
|
160
|
+
: skConfig.definition.build(rawKey);
|
|
108
161
|
}
|
|
109
|
-
|
|
110
162
|
return keyObj;
|
|
111
163
|
}
|
|
112
|
-
|
|
113
|
-
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Build index attributes for each defined GSI.
|
|
167
|
+
*/
|
|
168
|
+
public buildIndexes(rawItem: Partial<T>): Record<string, any> {
|
|
114
169
|
const indexAttributes: Record<string, any> = {};
|
|
115
|
-
|
|
116
170
|
if (this.keys.gsis) {
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
171
|
+
for (const gsiName in this.keys.gsis) {
|
|
172
|
+
const gsiConfig = this.keys.gsis[gsiName];
|
|
173
|
+
|
|
174
|
+
// Compute primary index attribute.
|
|
175
|
+
const primaryConfig = gsiConfig.primary;
|
|
176
|
+
indexAttributes[primaryConfig.name] =
|
|
177
|
+
(typeof primaryConfig.definition === 'string' ||
|
|
178
|
+
typeof primaryConfig.definition === 'number' ||
|
|
179
|
+
typeof primaryConfig.definition === 'symbol')
|
|
180
|
+
? String((rawItem as any)[primaryConfig.definition])
|
|
181
|
+
: primaryConfig.definition.build(rawItem);
|
|
182
|
+
|
|
183
|
+
// Compute sort index attribute if provided.
|
|
184
|
+
if (gsiConfig.sort) {
|
|
185
|
+
const sortConfig = gsiConfig.sort;
|
|
186
|
+
indexAttributes[sortConfig.name] =
|
|
187
|
+
(typeof sortConfig.definition === 'string' ||
|
|
188
|
+
typeof sortConfig.definition === 'number' ||
|
|
189
|
+
typeof sortConfig.definition === 'symbol')
|
|
190
|
+
? String((rawItem as any)[sortConfig.definition])
|
|
191
|
+
: sortConfig.definition.build(rawItem);
|
|
123
192
|
}
|
|
124
|
-
}
|
|
193
|
+
}
|
|
125
194
|
}
|
|
126
|
-
|
|
127
195
|
return indexAttributes;
|
|
128
196
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Create an item:
|
|
200
|
+
* - Computes primary key and index attributes,
|
|
201
|
+
* - Optionally injects timestamps,
|
|
202
|
+
* - Validates the item and writes it to DynamoDB.
|
|
203
|
+
*/
|
|
204
|
+
public create(item: T): CreateBuilder<T> {
|
|
205
|
+
return new CreateBuilder<T>(this, item);
|
|
132
206
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get an item by its primary key.
|
|
210
|
+
*/
|
|
211
|
+
public get(rawKey: Partial<T>): GetBuilder<T> {
|
|
212
|
+
return new GetBuilder<T>(this, rawKey);
|
|
136
213
|
}
|
|
137
214
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
): UpdateBuilder<
|
|
142
|
-
return new UpdateBuilder<
|
|
215
|
+
/**
|
|
216
|
+
* Update an item.
|
|
217
|
+
*/
|
|
218
|
+
public update(key: Partial<T>, expectedVersion?: number): UpdateBuilder<T> {
|
|
219
|
+
return new UpdateBuilder<T>(this, key, expectedVersion);
|
|
143
220
|
}
|
|
144
221
|
|
|
145
|
-
|
|
146
|
-
|
|
222
|
+
/**
|
|
223
|
+
* Delete an item.
|
|
224
|
+
*/
|
|
225
|
+
public delete(rawKey: Partial<T>): DeleteBuilder<T> {
|
|
226
|
+
return new DeleteBuilder<T>(this, rawKey);
|
|
147
227
|
}
|
|
148
228
|
|
|
149
|
-
|
|
150
|
-
|
|
229
|
+
/**
|
|
230
|
+
* Query items.
|
|
231
|
+
*/
|
|
232
|
+
public query(key: Partial<T>): QueryBuilder<T> {
|
|
233
|
+
return new QueryBuilder<T>(this, key);
|
|
151
234
|
}
|
|
152
235
|
|
|
153
|
-
|
|
154
|
-
|
|
236
|
+
/**
|
|
237
|
+
* Scan for items.
|
|
238
|
+
*/
|
|
239
|
+
public scan(): ScanBuilder<T> {
|
|
240
|
+
return new ScanBuilder<T>(this);
|
|
155
241
|
}
|
|
156
|
-
}
|
|
242
|
+
}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
import { AttributeValue, Put, TransactWriteItem } from '@aws-sdk/client-dynamodb';
|
|
2
3
|
import { BetterDDB } from '../betterddb';
|
|
3
|
-
import {
|
|
4
|
+
import { PutCommand, TransactWriteCommand } from '@aws-sdk/lib-dynamodb';
|
|
4
5
|
|
|
5
|
-
export class CreateBuilder<
|
|
6
|
-
private extraTransactItems:
|
|
6
|
+
export class CreateBuilder<T> {
|
|
7
|
+
private extraTransactItems: TransactWriteItem[] = [];
|
|
7
8
|
|
|
8
|
-
constructor(private parent: BetterDDB<
|
|
9
|
+
constructor(private parent: BetterDDB<T>, private item: T) {}
|
|
9
10
|
|
|
10
|
-
public async execute(): Promise<
|
|
11
|
+
public async execute(): Promise<T> {
|
|
11
12
|
if (this.extraTransactItems.length > 0) {
|
|
12
13
|
// Build our update transaction item.
|
|
13
14
|
const myTransactItem = this.toTransactPut();
|
|
14
15
|
// Combine with extra transaction items.
|
|
15
16
|
const allItems = [...this.extraTransactItems, myTransactItem];
|
|
16
|
-
await this.parent.getClient().
|
|
17
|
+
await this.parent.getClient().send(new TransactWriteCommand({
|
|
17
18
|
TransactItems: allItems
|
|
18
|
-
})
|
|
19
|
+
}));
|
|
19
20
|
// After transaction, retrieve the updated item.
|
|
20
21
|
const result = await this.parent.get(this.item).execute();
|
|
21
22
|
if (result === null) {
|
|
@@ -26,30 +27,30 @@ export class CreateBuilder<S extends z.ZodType<any>> {
|
|
|
26
27
|
let item = this.item;
|
|
27
28
|
if (this.parent.getAutoTimestamps()) {
|
|
28
29
|
const now = new Date().toISOString();
|
|
29
|
-
item = { ...item, createdAt: now, updatedAt: now } as
|
|
30
|
+
item = { ...item, createdAt: now, updatedAt: now } as T;
|
|
30
31
|
}
|
|
31
32
|
// Validate the item using the schema.
|
|
32
33
|
const validated = this.parent.getSchema().parse(item);
|
|
33
34
|
let finalItem = { ...validated };
|
|
34
35
|
|
|
35
36
|
// Compute and merge primary key.
|
|
36
|
-
const computedKeys = this.parent.buildKey(validated);
|
|
37
|
+
const computedKeys = this.parent.buildKey(validated as Partial<T>);
|
|
37
38
|
finalItem = { ...finalItem, ...computedKeys };
|
|
38
39
|
|
|
39
40
|
// Compute and merge index attributes.
|
|
40
|
-
const indexAttributes = this.parent.buildIndexes(validated);
|
|
41
|
+
const indexAttributes = this.parent.buildIndexes(validated as Partial<T>);
|
|
41
42
|
finalItem = { ...finalItem, ...indexAttributes };
|
|
42
43
|
|
|
43
|
-
await this.parent.getClient().
|
|
44
|
+
await this.parent.getClient().send(new PutCommand({
|
|
44
45
|
TableName: this.parent.getTableName(),
|
|
45
|
-
Item: finalItem
|
|
46
|
-
})
|
|
46
|
+
Item: finalItem
|
|
47
|
+
}));
|
|
47
48
|
|
|
48
|
-
return validated;
|
|
49
|
+
return validated as T;
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
public transactWrite(ops:
|
|
53
|
+
public transactWrite(ops: TransactWriteItem[] | TransactWriteItem): this {
|
|
53
54
|
if (Array.isArray(ops)) {
|
|
54
55
|
this.extraTransactItems.push(...ops);
|
|
55
56
|
} else {
|
|
@@ -58,26 +59,26 @@ export class CreateBuilder<S extends z.ZodType<any>> {
|
|
|
58
59
|
return this;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
public toTransactPut():
|
|
62
|
-
const putItem:
|
|
62
|
+
public toTransactPut(): TransactWriteItem{
|
|
63
|
+
const putItem: Put = {
|
|
63
64
|
TableName: this.parent.getTableName(),
|
|
64
|
-
Item: this.item as
|
|
65
|
+
Item: this.item as Record<string, AttributeValue>,
|
|
65
66
|
};
|
|
66
67
|
return { Put: putItem };
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
public then<TResult1 =
|
|
70
|
-
onfulfilled?: ((value:
|
|
70
|
+
public then<TResult1 = T, TResult2 = never>(
|
|
71
|
+
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
|
71
72
|
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
|
|
72
73
|
): Promise<TResult1 | TResult2> {
|
|
73
74
|
return this.execute().then(onfulfilled, onrejected);
|
|
74
75
|
}
|
|
75
76
|
public catch<TResult = never>(
|
|
76
77
|
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
|
|
77
|
-
): Promise<
|
|
78
|
+
): Promise<T | TResult> {
|
|
78
79
|
return this.execute().catch(onrejected);
|
|
79
80
|
}
|
|
80
|
-
public finally(onfinally?: (() => void) | null): Promise<
|
|
81
|
+
public finally(onfinally?: (() => void) | null): Promise<T> {
|
|
81
82
|
return this.execute().finally(onfinally);
|
|
82
83
|
}
|
|
83
84
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { DynamoDB } from 'aws-sdk';
|
|
2
1
|
import { BetterDDB } from '../betterddb';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export class DeleteBuilder<
|
|
2
|
+
import { TransactWriteItem, DeleteItemInput } from '@aws-sdk/client-dynamodb';
|
|
3
|
+
import { TransactWriteCommand, DeleteCommand } from '@aws-sdk/lib-dynamodb';
|
|
4
|
+
export class DeleteBuilder<T> {
|
|
6
5
|
private condition?: { expression: string; attributeValues: Record<string, any> };
|
|
7
|
-
private extraTransactItems:
|
|
8
|
-
constructor(private parent: BetterDDB<
|
|
6
|
+
private extraTransactItems: TransactWriteItem[] = [];
|
|
7
|
+
constructor(private parent: BetterDDB<T>, private key: Partial<T>) {}
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Specify a condition expression for the delete operation.
|
|
@@ -26,16 +25,16 @@ export class DeleteBuilder<S extends z.ZodType<any>> {
|
|
|
26
25
|
const myTransactItem = this.toTransactDelete();
|
|
27
26
|
// Combine with extra transaction items.
|
|
28
27
|
const allItems = [...this.extraTransactItems, myTransactItem];
|
|
29
|
-
await this.parent.getClient().
|
|
28
|
+
await this.parent.getClient().send(new TransactWriteCommand({
|
|
30
29
|
TransactItems: allItems
|
|
31
|
-
})
|
|
30
|
+
}));
|
|
32
31
|
// After transaction, retrieve the updated item.
|
|
33
32
|
const result = await this.parent.get(this.key).execute();
|
|
34
33
|
if (result === null) {
|
|
35
34
|
throw new Error('Item not found after transaction delete');
|
|
36
35
|
}
|
|
37
36
|
} else {
|
|
38
|
-
const params:
|
|
37
|
+
const params: DeleteItemInput = {
|
|
39
38
|
TableName: this.parent.getTableName(),
|
|
40
39
|
Key: this.parent.buildKey(this.key)
|
|
41
40
|
};
|
|
@@ -43,11 +42,11 @@ export class DeleteBuilder<S extends z.ZodType<any>> {
|
|
|
43
42
|
params.ConditionExpression = this.condition.expression;
|
|
44
43
|
params.ExpressionAttributeValues = this.condition.attributeValues;
|
|
45
44
|
}
|
|
46
|
-
await this.parent.getClient().
|
|
45
|
+
await this.parent.getClient().send(new DeleteCommand(params));
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
public transactWrite(ops:
|
|
49
|
+
public transactWrite(ops: TransactWriteItem[] | TransactWriteItem): this {
|
|
51
50
|
if (Array.isArray(ops)) {
|
|
52
51
|
this.extraTransactItems.push(...ops);
|
|
53
52
|
} else {
|
|
@@ -56,8 +55,8 @@ export class DeleteBuilder<S extends z.ZodType<any>> {
|
|
|
56
55
|
return this;
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
public toTransactDelete():
|
|
60
|
-
const deleteItem:
|
|
58
|
+
public toTransactDelete(): TransactWriteItem {
|
|
59
|
+
const deleteItem: DeleteItemInput = {
|
|
61
60
|
TableName: this.parent.getTableName(),
|
|
62
61
|
Key: this.parent.buildKey(this.key)
|
|
63
62
|
};
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import { DynamoDB } from 'aws-sdk';
|
|
2
1
|
import { BetterDDB } from '../betterddb';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export class GetBuilder<
|
|
2
|
+
import { TransactGetCommand, GetCommand } from '@aws-sdk/lib-dynamodb';
|
|
3
|
+
import { GetItemInput, TransactGetItem } from '@aws-sdk/client-dynamodb';
|
|
4
|
+
export class GetBuilder<T> {
|
|
6
5
|
private projectionExpression?: string;
|
|
7
6
|
private expressionAttributeNames: Record<string, string> = {};
|
|
8
|
-
private extraTransactItems:
|
|
9
|
-
constructor(private parent: BetterDDB<
|
|
7
|
+
private extraTransactItems: TransactGetItem[] = [];
|
|
8
|
+
constructor(private parent: BetterDDB<T>, private key: Partial<T>) {}
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Specify a projection by providing an array of attribute names.
|
|
13
12
|
*/
|
|
14
|
-
public withProjection(attributes: (keyof
|
|
13
|
+
public withProjection(attributes: (keyof T)[]): this {
|
|
15
14
|
this.projectionExpression = attributes.map(attr => `#${String(attr)}`).join(', ');
|
|
16
15
|
for (const attr of attributes) {
|
|
17
16
|
this.expressionAttributeNames[`#${String(attr)}`] = String(attr);
|
|
@@ -19,20 +18,20 @@ export class GetBuilder<S extends z.ZodType<any>> {
|
|
|
19
18
|
return this;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
public async execute(): Promise<
|
|
21
|
+
public async execute(): Promise<T | null> {
|
|
23
22
|
if (this.extraTransactItems.length > 0) {
|
|
24
23
|
// Build our update transaction item.
|
|
25
24
|
const myTransactItem = this.toTransactGet();
|
|
26
25
|
// Combine with extra transaction items.
|
|
27
26
|
const allItems = [...this.extraTransactItems, myTransactItem];
|
|
28
|
-
await this.parent.getClient().
|
|
27
|
+
await this.parent.getClient().send(new TransactGetCommand({
|
|
29
28
|
TransactItems: allItems
|
|
30
|
-
})
|
|
29
|
+
}));
|
|
31
30
|
// After transaction, retrieve the updated item.
|
|
32
31
|
const result = await this.parent.get(this.key).execute();
|
|
33
32
|
return result;
|
|
34
33
|
} else {
|
|
35
|
-
const params:
|
|
34
|
+
const params: GetItemInput = {
|
|
36
35
|
TableName: this.parent.getTableName(),
|
|
37
36
|
Key: this.parent.buildKey(this.key)
|
|
38
37
|
};
|
|
@@ -40,13 +39,13 @@ export class GetBuilder<S extends z.ZodType<any>> {
|
|
|
40
39
|
params.ProjectionExpression = this.projectionExpression;
|
|
41
40
|
params.ExpressionAttributeNames = this.expressionAttributeNames;
|
|
42
41
|
}
|
|
43
|
-
const result = await this.parent.getClient().
|
|
42
|
+
const result = await this.parent.getClient().send(new GetCommand(params));
|
|
44
43
|
if (!result.Item) return null;
|
|
45
|
-
return this.parent.getSchema().parse(result.Item);
|
|
44
|
+
return this.parent.getSchema().parse(result.Item) as T;
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
public transactGet(ops:
|
|
48
|
+
public transactGet(ops: TransactGetItem[] | TransactGetItem): this {
|
|
50
49
|
if (Array.isArray(ops)) {
|
|
51
50
|
this.extraTransactItems.push(...ops);
|
|
52
51
|
} else {
|
|
@@ -55,8 +54,8 @@ export class GetBuilder<S extends z.ZodType<any>> {
|
|
|
55
54
|
return this;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
public toTransactGet():
|
|
59
|
-
const getItem:
|
|
57
|
+
public toTransactGet(): TransactGetItem {
|
|
58
|
+
const getItem: GetItemInput = {
|
|
60
59
|
TableName: this.parent.getTableName(),
|
|
61
60
|
Key: this.parent.buildKey(this.key)
|
|
62
61
|
};
|
|
@@ -67,18 +66,18 @@ export class GetBuilder<S extends z.ZodType<any>> {
|
|
|
67
66
|
return { Get: getItem };
|
|
68
67
|
}
|
|
69
68
|
|
|
70
|
-
public then<TResult1 =
|
|
71
|
-
onfulfilled?: ((value:
|
|
69
|
+
public then<TResult1 = T | null, TResult2 = never>(
|
|
70
|
+
onfulfilled?: ((value: T | null) => TResult1 | PromiseLike<TResult1>) | null,
|
|
72
71
|
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
|
|
73
72
|
): Promise<TResult1 | TResult2> {
|
|
74
73
|
return this.execute().then(onfulfilled, onrejected);
|
|
75
74
|
}
|
|
76
75
|
public catch<TResult = never>(
|
|
77
76
|
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
|
|
78
|
-
): Promise<
|
|
77
|
+
): Promise<T | null | TResult> {
|
|
79
78
|
return this.execute().catch(onrejected);
|
|
80
79
|
}
|
|
81
|
-
public finally(onfinally?: (() => void) | null): Promise<
|
|
80
|
+
public finally(onfinally?: (() => void) | null): Promise<T | null> {
|
|
82
81
|
return this.execute().finally(onfinally);
|
|
83
82
|
}
|
|
84
83
|
}
|