betterddb 0.8.0 → 0.8.2
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/dist/src/betterddb.d.ts +137 -0
- package/dist/src/betterddb.d.ts.map +1 -0
- package/dist/src/betterddb.js +165 -0
- package/dist/src/betterddb.js.map +1 -0
- package/dist/src/builders/batch-get-builder.d.ts +16 -0
- package/dist/src/builders/batch-get-builder.d.ts.map +1 -0
- package/dist/src/builders/batch-get-builder.js +54 -0
- package/dist/src/builders/batch-get-builder.js.map +1 -0
- package/dist/src/builders/create-builder.d.ts +12 -0
- package/dist/src/builders/create-builder.d.ts.map +1 -0
- package/dist/src/builders/create-builder.js +84 -0
- package/dist/src/builders/create-builder.js.map +1 -0
- package/dist/src/builders/delete-builder.d.ts +18 -0
- package/dist/src/builders/delete-builder.d.ts.map +1 -0
- package/dist/src/builders/delete-builder.js +75 -0
- package/dist/src/builders/delete-builder.js.map +1 -0
- package/dist/src/builders/get-builder.d.ts +18 -0
- package/dist/src/builders/get-builder.d.ts.map +1 -0
- package/dist/src/builders/get-builder.js +76 -0
- package/dist/src/builders/get-builder.js.map +1 -0
- package/dist/src/builders/index.d.ts +8 -0
- package/dist/src/builders/index.d.ts.map +1 -0
- package/{src/builders/index.ts → dist/src/builders/index.js} +1 -0
- package/dist/src/builders/index.js.map +1 -0
- package/dist/src/builders/query-builder.d.ts +29 -0
- package/dist/src/builders/query-builder.d.ts.map +1 -0
- package/dist/src/builders/query-builder.js +171 -0
- package/dist/src/builders/query-builder.js.map +1 -0
- package/dist/src/builders/scan-builder.d.ts +21 -0
- package/dist/src/builders/scan-builder.d.ts.map +1 -0
- package/dist/src/builders/scan-builder.js +76 -0
- package/dist/src/builders/scan-builder.js.map +1 -0
- package/dist/src/builders/update-builder.d.ts +37 -0
- package/dist/src/builders/update-builder.d.ts.map +1 -0
- package/dist/src/builders/update-builder.js +301 -0
- package/dist/src/builders/update-builder.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/{src/index.ts → dist/src/index.js} +1 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/operator.d.ts +3 -0
- package/dist/src/operator.d.ts.map +1 -0
- package/dist/src/operator.js +28 -0
- package/dist/src/operator.js.map +1 -0
- package/dist/src/types/index.d.ts +2 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/{src/types/index.ts → dist/src/types/index.js} +1 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/paginated-result.d.ts +6 -0
- package/dist/src/types/paginated-result.d.ts.map +1 -0
- package/dist/src/types/paginated-result.js +2 -0
- package/dist/src/types/paginated-result.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +9 -8
- package/.github/workflows/npm-publish.yml +0 -33
- package/.github/workflows/test.yml +0 -42
- package/CONTRIBUTING.md +0 -225
- package/LICENCSE +0 -21
- package/babel.config.cjs +0 -6
- package/docker-compose.yml +0 -16
- package/eslint.config.mjs +0 -29
- package/jest.config.cjs +0 -17
- package/prettier.config.js +0 -6
- package/src/betterddb.ts +0 -267
- package/src/builders/batch-get-builder.ts +0 -56
- package/src/builders/create-builder.ts +0 -97
- package/src/builders/delete-builder.ts +0 -87
- package/src/builders/get-builder.ts +0 -78
- package/src/builders/query-builder.ts +0 -242
- package/src/builders/scan-builder.ts +0 -98
- package/src/builders/update-builder.ts +0 -363
- package/src/operator.ts +0 -43
- package/src/types/paginated-result.ts +0 -6
- package/test/batch-get.test.ts +0 -122
- package/test/create.test.ts +0 -121
- package/test/delete.test.ts +0 -93
- package/test/get.test.ts +0 -98
- package/test/query.test.ts +0 -206
- package/test/scan.test.ts +0 -130
- package/test/update.test.ts +0 -355
- package/test/utils/table-setup.ts +0 -62
- package/tsconfig.json +0 -23
package/test/update.test.ts
DELETED
|
@@ -1,355 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { BetterDDB } from "../src/betterddb";
|
|
3
|
-
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
|
|
4
|
-
import { createTestTable, deleteTestTable } from "./utils/table-setup";
|
|
5
|
-
import {
|
|
6
|
-
DynamoDB,
|
|
7
|
-
GlobalSecondaryIndex,
|
|
8
|
-
AttributeValue,
|
|
9
|
-
} from "@aws-sdk/client-dynamodb";
|
|
10
|
-
import {
|
|
11
|
-
KeySchemaElement,
|
|
12
|
-
AttributeDefinition,
|
|
13
|
-
} from "@aws-sdk/client-dynamodb";
|
|
14
|
-
const TEST_TABLE = "update-test-table";
|
|
15
|
-
const ENDPOINT = "http://localhost:4566";
|
|
16
|
-
const REGION = "us-east-1";
|
|
17
|
-
const ENTITY_TYPE = "USER";
|
|
18
|
-
const PRIMARY_KEY = "pk";
|
|
19
|
-
const PRIMARY_KEY_TYPE = "S";
|
|
20
|
-
const SORT_KEY = "sk";
|
|
21
|
-
const SORT_KEY_TYPE = "S";
|
|
22
|
-
const GSI_NAME = "EmailIndex";
|
|
23
|
-
const GSI_PRIMARY_KEY = "gsi1pk";
|
|
24
|
-
const GSI_SORT_KEY = "gsi1sk";
|
|
25
|
-
const KEY_SCHEMA = [
|
|
26
|
-
{ AttributeName: PRIMARY_KEY, KeyType: "HASH" },
|
|
27
|
-
{ AttributeName: SORT_KEY, KeyType: "RANGE" },
|
|
28
|
-
] as KeySchemaElement[];
|
|
29
|
-
const ATTRIBUTE_DEFINITIONS = [
|
|
30
|
-
{ AttributeName: PRIMARY_KEY, AttributeType: PRIMARY_KEY_TYPE },
|
|
31
|
-
{ AttributeName: SORT_KEY, AttributeType: SORT_KEY_TYPE },
|
|
32
|
-
{ AttributeName: GSI_PRIMARY_KEY, AttributeType: PRIMARY_KEY_TYPE },
|
|
33
|
-
{ AttributeName: GSI_SORT_KEY, AttributeType: SORT_KEY_TYPE },
|
|
34
|
-
] as AttributeDefinition[];
|
|
35
|
-
const GSIS = [
|
|
36
|
-
{
|
|
37
|
-
IndexName: GSI_NAME,
|
|
38
|
-
KeySchema: [
|
|
39
|
-
{ AttributeName: GSI_PRIMARY_KEY, KeyType: "HASH" },
|
|
40
|
-
{ AttributeName: GSI_SORT_KEY, KeyType: "RANGE" },
|
|
41
|
-
],
|
|
42
|
-
Projection: {
|
|
43
|
-
ProjectionType: "ALL",
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
] as GlobalSecondaryIndex[];
|
|
47
|
-
const client = DynamoDBDocumentClient.from(
|
|
48
|
-
new DynamoDB({
|
|
49
|
-
region: REGION,
|
|
50
|
-
endpoint: ENDPOINT,
|
|
51
|
-
}),
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
const UserSchema = z.object({
|
|
55
|
-
id: z.string(),
|
|
56
|
-
name: z.string(),
|
|
57
|
-
email: z.string().email(),
|
|
58
|
-
nickname: z.string().optional(),
|
|
59
|
-
points: z.number().optional(),
|
|
60
|
-
tags: z.set(z.string()).optional(),
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
type User = z.infer<typeof UserSchema>;
|
|
64
|
-
|
|
65
|
-
const userDdb = new BetterDDB<User>({
|
|
66
|
-
schema: UserSchema,
|
|
67
|
-
tableName: TEST_TABLE,
|
|
68
|
-
entityType: ENTITY_TYPE,
|
|
69
|
-
keys: {
|
|
70
|
-
primary: { name: PRIMARY_KEY, definition: { build: (raw) => raw.id! } },
|
|
71
|
-
sort: { name: SORT_KEY, definition: { build: (raw) => raw.email! } },
|
|
72
|
-
gsis: {
|
|
73
|
-
EmailIndex: {
|
|
74
|
-
name: GSI_NAME,
|
|
75
|
-
primary: {
|
|
76
|
-
name: GSI_PRIMARY_KEY,
|
|
77
|
-
definition: { build: (raw) => "EMAIL" },
|
|
78
|
-
},
|
|
79
|
-
sort: {
|
|
80
|
-
name: GSI_SORT_KEY,
|
|
81
|
-
definition: { build: (raw) => `EMAIL#${raw.email}` },
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
client,
|
|
87
|
-
timestamps: true,
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
beforeAll(async () => {
|
|
91
|
-
await createTestTable(TEST_TABLE, KEY_SCHEMA, ATTRIBUTE_DEFINITIONS, GSIS);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
beforeEach(async () => {
|
|
95
|
-
const initialUser: User = {
|
|
96
|
-
id: "user-123",
|
|
97
|
-
name: "John Doe",
|
|
98
|
-
email: "john@example.com",
|
|
99
|
-
};
|
|
100
|
-
await userDdb.create(initialUser).execute();
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
afterEach(async () => {
|
|
104
|
-
await userDdb.delete({ id: "user-123", email: "john@example.com" }).execute();
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
afterAll(async () => {
|
|
108
|
-
await deleteTestTable(TEST_TABLE);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
describe("BetterDDB - Update Operation", () => {
|
|
112
|
-
it("should update an existing item using UpdateBuilder", async () => {
|
|
113
|
-
const updatedUser = await userDdb
|
|
114
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
115
|
-
.set({ name: "Jane Doe" })
|
|
116
|
-
.execute();
|
|
117
|
-
expect(updatedUser.name).toBe("Jane Doe");
|
|
118
|
-
expect(updatedUser.email).toBe("john@example.com");
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it("should add optional attributes and remove them", async () => {
|
|
122
|
-
// First add the optional attribute
|
|
123
|
-
await userDdb
|
|
124
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
125
|
-
.set({ points: 10, name: "John Doe" }) // Maintain required field
|
|
126
|
-
.execute();
|
|
127
|
-
|
|
128
|
-
// Then remove it
|
|
129
|
-
const updatedUser = await userDdb
|
|
130
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
131
|
-
.remove(["points"])
|
|
132
|
-
.execute();
|
|
133
|
-
|
|
134
|
-
expect(updatedUser.points).toBeUndefined();
|
|
135
|
-
expect(updatedUser.name).toBe("John Doe"); // Required field remains
|
|
136
|
-
expect(updatedUser.email).toBe("john@example.com"); // Required field remains
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it("should add to a number attribute", async () => {
|
|
140
|
-
// First set initial value with all required fields
|
|
141
|
-
await userDdb
|
|
142
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
143
|
-
.set({ points: 10, name: "John Doe" })
|
|
144
|
-
.execute();
|
|
145
|
-
|
|
146
|
-
// Then add to it
|
|
147
|
-
const updatedUser = await userDdb
|
|
148
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
149
|
-
.add({ points: 5 })
|
|
150
|
-
.execute();
|
|
151
|
-
|
|
152
|
-
expect(updatedUser.points).toBe(15);
|
|
153
|
-
expect(updatedUser.name).toBe("John Doe"); // Required field remains
|
|
154
|
-
expect(updatedUser.email).toBe("john@example.com"); // Required field remains
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it("should add and remove from a set attribute", async () => {
|
|
158
|
-
// First set initial value with all required fields
|
|
159
|
-
await userDdb
|
|
160
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
161
|
-
.set({ tags: new Set(["tag1"]), name: "John Doe" })
|
|
162
|
-
.execute();
|
|
163
|
-
|
|
164
|
-
// Add to set
|
|
165
|
-
let updatedUser = await userDdb
|
|
166
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
167
|
-
.add({ tags: new Set(["tag2"]) })
|
|
168
|
-
.execute();
|
|
169
|
-
|
|
170
|
-
expect(updatedUser.tags).toEqual(new Set(["tag1", "tag2"]));
|
|
171
|
-
expect(updatedUser.name).toBe("John Doe"); // Required field remains
|
|
172
|
-
expect(updatedUser.email).toBe("john@example.com"); // Required field remains
|
|
173
|
-
|
|
174
|
-
// Delete from set
|
|
175
|
-
updatedUser = await userDdb
|
|
176
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
177
|
-
.delete({ tags: new Set(["tag1"]) })
|
|
178
|
-
.execute();
|
|
179
|
-
|
|
180
|
-
expect(updatedUser.tags).toEqual(new Set(["tag2"]));
|
|
181
|
-
expect(updatedUser.name).toBe("John Doe"); // Required field remains
|
|
182
|
-
expect(updatedUser.email).toBe("john@example.com"); // Required field remains
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
it("should perform conditional updates", async () => {
|
|
186
|
-
// Update only if name matches
|
|
187
|
-
const updatedUser = await userDdb
|
|
188
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
189
|
-
.set({ name: "John Smith" })
|
|
190
|
-
.setCondition(
|
|
191
|
-
"#n = :n",
|
|
192
|
-
{
|
|
193
|
-
":n": "John Doe",
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
"#n": "name",
|
|
197
|
-
},
|
|
198
|
-
)
|
|
199
|
-
.execute();
|
|
200
|
-
|
|
201
|
-
expect(updatedUser.name).toBe("John Smith");
|
|
202
|
-
expect(updatedUser.email).toBe("john@example.com"); // Required field remains
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it("should fail conditional updates when condition is not met", async () => {
|
|
206
|
-
await expect(
|
|
207
|
-
userDdb
|
|
208
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
209
|
-
.set({ name: "John Smith" })
|
|
210
|
-
.setCondition(
|
|
211
|
-
"#n = :n",
|
|
212
|
-
{
|
|
213
|
-
":n": "Wrong Name",
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
"#n": "name",
|
|
217
|
-
},
|
|
218
|
-
)
|
|
219
|
-
.execute(),
|
|
220
|
-
).rejects.toThrow();
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it("should perform transaction updates", async () => {
|
|
224
|
-
// Create another user for the transaction
|
|
225
|
-
const newUser: User = {
|
|
226
|
-
id: "user-456",
|
|
227
|
-
name: "Alice",
|
|
228
|
-
email: "alice@example.com",
|
|
229
|
-
};
|
|
230
|
-
await userDdb.create(newUser).execute();
|
|
231
|
-
|
|
232
|
-
// Create a second update builder for the transaction
|
|
233
|
-
const secondUpdate = await userDdb
|
|
234
|
-
.update({ id: "user-456", email: "alice@example.com" })
|
|
235
|
-
.set({ name: "Alice Updated" })
|
|
236
|
-
.toTransactUpdate();
|
|
237
|
-
|
|
238
|
-
// Update both users in a transaction
|
|
239
|
-
const updatedUser = await userDdb
|
|
240
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
241
|
-
.set({ name: "John Updated" })
|
|
242
|
-
.transactWrite(secondUpdate)
|
|
243
|
-
.execute();
|
|
244
|
-
|
|
245
|
-
expect(updatedUser.name).toBe("John Updated");
|
|
246
|
-
expect(updatedUser.email).toBe("john@example.com"); // Required field remains
|
|
247
|
-
|
|
248
|
-
// Verify the other user was updated
|
|
249
|
-
const otherUser = await userDdb
|
|
250
|
-
.get({ id: "user-456", email: "alice@example.com" })
|
|
251
|
-
.execute();
|
|
252
|
-
expect(otherUser?.name).toBe("Alice Updated");
|
|
253
|
-
expect(otherUser?.email).toBe("alice@example.com"); // Required field remains
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
it("should fail validation when setting invalid values", async () => {
|
|
257
|
-
// This should fail at schema validation level
|
|
258
|
-
const builder = userDdb.update({
|
|
259
|
-
id: "user-123",
|
|
260
|
-
email: "john@example.com",
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
// The validation should happen immediately when setting invalid values
|
|
264
|
-
expect(() => builder.set({ email: "invalid-email" })).toThrow(z.ZodError);
|
|
265
|
-
|
|
266
|
-
// Verify the error message
|
|
267
|
-
try {
|
|
268
|
-
builder.set({ email: "invalid-email" });
|
|
269
|
-
fail("Should have thrown a validation error");
|
|
270
|
-
} catch (error) {
|
|
271
|
-
if (error instanceof z.ZodError) {
|
|
272
|
-
expect(error.errors[0].message).toBe("Invalid email");
|
|
273
|
-
} else {
|
|
274
|
-
fail("Expected ZodError");
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
it("should fail when updating non-existent item", async () => {
|
|
280
|
-
await expect(
|
|
281
|
-
userDdb
|
|
282
|
-
.update({ id: "non-existent", email: "none@example.com" })
|
|
283
|
-
.set({ name: "New Name" })
|
|
284
|
-
.execute(),
|
|
285
|
-
).rejects.toThrow();
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
it("should update index attributes when modifying indexed fields", async () => {
|
|
289
|
-
// First verify the initial state
|
|
290
|
-
const initialUser = await userDdb
|
|
291
|
-
.get({ id: "user-123", email: "john@example.com" })
|
|
292
|
-
.execute();
|
|
293
|
-
expect(initialUser).toBeTruthy();
|
|
294
|
-
|
|
295
|
-
// Update the email which should trigger index updates
|
|
296
|
-
const updatedUser = await userDdb
|
|
297
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
298
|
-
.set({ email: "john.updated@example.com" })
|
|
299
|
-
.execute();
|
|
300
|
-
|
|
301
|
-
// Verify the main attributes were updated
|
|
302
|
-
expect(updatedUser.email).toBe("john.updated@example.com");
|
|
303
|
-
expect(updatedUser.name).toBe("John Doe"); // Required field remains
|
|
304
|
-
|
|
305
|
-
// Verify the index attributes were updated
|
|
306
|
-
expect(updatedUser.email).toBe("john.updated@example.com");
|
|
307
|
-
|
|
308
|
-
// Verify we can query using the new index values
|
|
309
|
-
const queriedUser = await userDdb
|
|
310
|
-
.query({ email: "john.updated@example.com" })
|
|
311
|
-
.usingIndex(GSI_NAME)
|
|
312
|
-
.where("==", { email: "john.updated@example.com" })
|
|
313
|
-
.execute();
|
|
314
|
-
expect(queriedUser.items).toHaveLength(1);
|
|
315
|
-
expect(queriedUser.items[0].id).toBe("user-123");
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
it("should automatically convert empty strings and undefined to remove operations", async () => {
|
|
319
|
-
// First set initial values
|
|
320
|
-
await userDdb
|
|
321
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
322
|
-
.set({ name: "John Doe", points: 10, nickname: "John" })
|
|
323
|
-
.execute();
|
|
324
|
-
|
|
325
|
-
// Update with a mix of values - some to set, some to remove
|
|
326
|
-
const updatedUser = await userDdb
|
|
327
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
328
|
-
.set({
|
|
329
|
-
name: "", // Should trigger remove
|
|
330
|
-
points: undefined, // Should trigger remove
|
|
331
|
-
nickname: "", // Should trigger remove
|
|
332
|
-
email: "john@example.com", // Should remain (required field)
|
|
333
|
-
})
|
|
334
|
-
.execute();
|
|
335
|
-
|
|
336
|
-
// Fields should be removed, not null or undefined
|
|
337
|
-
expect(updatedUser.name).toBe(""); // Removed due to empty string
|
|
338
|
-
expect(updatedUser.points).toBeUndefined(); // Removed due to undefined
|
|
339
|
-
expect(updatedUser.nickname).toBeUndefined(); // Removed due to empty string
|
|
340
|
-
expect(updatedUser.email).toBe("john@example.com"); // Required field remains
|
|
341
|
-
|
|
342
|
-
// Now let's verify we can still set values normally
|
|
343
|
-
const finalUser = await userDdb
|
|
344
|
-
.update({ id: "user-123", email: "john@example.com" })
|
|
345
|
-
.set({
|
|
346
|
-
name: "New Name", // Should be set
|
|
347
|
-
points: 20, // Should be set
|
|
348
|
-
})
|
|
349
|
-
.execute();
|
|
350
|
-
|
|
351
|
-
expect(finalUser.name).toBe("New Name");
|
|
352
|
-
expect(finalUser.points).toBe(20);
|
|
353
|
-
expect(finalUser.email).toBe("john@example.com");
|
|
354
|
-
});
|
|
355
|
-
});
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { CreateTableCommandInput, DynamoDB } from "@aws-sdk/client-dynamodb";
|
|
2
|
-
|
|
3
|
-
export const createTestTable = async (
|
|
4
|
-
tableName: string,
|
|
5
|
-
keySchema: CreateTableCommandInput["KeySchema"],
|
|
6
|
-
attributeDefinitions: CreateTableCommandInput["AttributeDefinitions"],
|
|
7
|
-
gsis: CreateTableCommandInput["GlobalSecondaryIndexes"],
|
|
8
|
-
) => {
|
|
9
|
-
const dynamoDB = new DynamoDB({
|
|
10
|
-
region: "us-east-1",
|
|
11
|
-
endpoint: "http://localhost:4566",
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
console.log("Creating DynamoDB table in LocalStack...");
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
await dynamoDB.createTable({
|
|
18
|
-
TableName: tableName,
|
|
19
|
-
KeySchema: keySchema,
|
|
20
|
-
AttributeDefinitions: attributeDefinitions,
|
|
21
|
-
BillingMode: "PAY_PER_REQUEST",
|
|
22
|
-
GlobalSecondaryIndexes: gsis,
|
|
23
|
-
});
|
|
24
|
-
} catch (error: unknown) {
|
|
25
|
-
if ((error as { code?: string }).code === "ResourceInUseException") {
|
|
26
|
-
console.log("Table already exists, skipping creation.");
|
|
27
|
-
} else {
|
|
28
|
-
throw error;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Wait for the table to become active.
|
|
33
|
-
let attempts = 0;
|
|
34
|
-
while (attempts < 60) {
|
|
35
|
-
// wait up to 15 seconds
|
|
36
|
-
const { Table } = await dynamoDB.describeTable({ TableName: tableName });
|
|
37
|
-
if (Table?.TableStatus === "ACTIVE") {
|
|
38
|
-
console.log("DynamoDB table is ready.");
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
console.log("Waiting for table to become ACTIVE...");
|
|
42
|
-
await new Promise((res) => setTimeout(res, 250));
|
|
43
|
-
attempts++;
|
|
44
|
-
}
|
|
45
|
-
throw new Error("Table did not become active in time.");
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
export const deleteTestTable = async (tableName: string) => {
|
|
49
|
-
const dynamoDB = new DynamoDB({
|
|
50
|
-
region: "us-east-1",
|
|
51
|
-
endpoint: "http://localhost:4566",
|
|
52
|
-
});
|
|
53
|
-
try {
|
|
54
|
-
await dynamoDB.deleteTable({ TableName: tableName });
|
|
55
|
-
} catch (error: unknown) {
|
|
56
|
-
if ((error as { code?: string }).code === "ResourceNotFoundException") {
|
|
57
|
-
console.log("Table not found during deletion.");
|
|
58
|
-
} else {
|
|
59
|
-
throw error;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
};
|
package/tsconfig.json
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"esModuleInterop": true,
|
|
4
|
-
"skipLibCheck": true,
|
|
5
|
-
"target": "es2022",
|
|
6
|
-
"allowJs": true,
|
|
7
|
-
"resolveJsonModule": true,
|
|
8
|
-
"moduleDetection": "force",
|
|
9
|
-
"isolatedModules": true,
|
|
10
|
-
"verbatimModuleSyntax": true,
|
|
11
|
-
"strict": true,
|
|
12
|
-
"noUncheckedIndexedAccess": true,
|
|
13
|
-
"noImplicitOverride": true,
|
|
14
|
-
"module": "NodeNext",
|
|
15
|
-
"outDir": "dist",
|
|
16
|
-
"sourceMap": true,
|
|
17
|
-
"composite": true,
|
|
18
|
-
"declarationMap": true,
|
|
19
|
-
"rootDir": "."
|
|
20
|
-
},
|
|
21
|
-
"include": ["src/**/*", "test/**/*"],
|
|
22
|
-
"exclude": ["node_modules", "dist"]
|
|
23
|
-
}
|