dyno-table 2.0.2 → 2.1.1
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 +126 -0
- package/dist/builders/condition-check-builder.cjs.map +1 -1
- package/dist/builders/condition-check-builder.js.map +1 -1
- package/dist/builders/delete-builder.cjs.map +1 -1
- package/dist/builders/delete-builder.js.map +1 -1
- package/dist/builders/paginator.cjs.map +1 -1
- package/dist/builders/paginator.js.map +1 -1
- package/dist/builders/put-builder.cjs.map +1 -1
- package/dist/builders/put-builder.js.map +1 -1
- package/dist/builders/query-builder.cjs +44 -21
- package/dist/builders/query-builder.cjs.map +1 -1
- package/dist/builders/query-builder.d.cts +1 -1
- package/dist/builders/query-builder.d.ts +1 -1
- package/dist/builders/query-builder.js +44 -21
- package/dist/builders/query-builder.js.map +1 -1
- package/dist/builders/transaction-builder.cjs.map +1 -1
- package/dist/builders/transaction-builder.js.map +1 -1
- package/dist/builders/update-builder.cjs.map +1 -1
- package/dist/builders/update-builder.js.map +1 -1
- package/dist/conditions.cjs.map +1 -1
- package/dist/conditions.js.map +1 -1
- package/dist/entity.cjs +196 -47
- package/dist/entity.cjs.map +1 -1
- package/dist/entity.d.cts +19 -7
- package/dist/entity.d.ts +19 -7
- package/dist/entity.js +196 -47
- package/dist/entity.js.map +1 -1
- package/dist/index.cjs +246 -61
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +246 -61
- package/dist/index.js.map +1 -1
- package/dist/{query-builder-BNWRCrJW.d.ts → query-builder-CUWdavZw.d.ts} +2 -0
- package/dist/{query-builder-DZ9JKgBN.d.cts → query-builder-DoZzZz_c.d.cts} +2 -0
- package/dist/{table-BhEeYauU.d.ts → table-4UxlW_wD.d.ts} +2 -1
- package/dist/{table-BpNOboD9.d.cts → table-D-xNCVFa.d.cts} +2 -1
- package/dist/table.cjs +58 -22
- package/dist/table.cjs.map +1 -1
- package/dist/table.d.cts +2 -2
- package/dist/table.d.ts +2 -2
- package/dist/table.js +58 -22
- package/dist/table.js.map +1 -1
- package/dist/types.d.cts +9 -2
- package/dist/types.d.ts +9 -2
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
package/dist/entity.js
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
// src/conditions.ts
|
|
2
|
-
var createComparisonCondition = (type) => (attr, value) => ({
|
|
3
|
-
type,
|
|
4
|
-
attr,
|
|
5
|
-
value
|
|
6
|
-
});
|
|
7
|
-
var eq = createComparisonCondition("eq");
|
|
8
|
-
|
|
9
1
|
// src/builders/entity-aware-builders.ts
|
|
10
2
|
function createEntityAwareBuilder(builder, entityName) {
|
|
11
3
|
return new Proxy(builder, {
|
|
@@ -34,27 +26,140 @@ function createEntityAwareDeleteBuilder(builder, entityName) {
|
|
|
34
26
|
return createEntityAwareBuilder(builder, entityName);
|
|
35
27
|
}
|
|
36
28
|
|
|
37
|
-
// src/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
29
|
+
// src/conditions.ts
|
|
30
|
+
var createComparisonCondition = (type) => (attr, value) => ({
|
|
31
|
+
type,
|
|
32
|
+
attr,
|
|
33
|
+
value
|
|
34
|
+
});
|
|
35
|
+
var eq = createComparisonCondition("eq");
|
|
36
|
+
|
|
37
|
+
// src/entity/ddb-indexing.ts
|
|
38
|
+
var IndexBuilder = class {
|
|
39
|
+
/**
|
|
40
|
+
* Creates a new IndexBuilder instance
|
|
41
|
+
*
|
|
42
|
+
* @param table - The DynamoDB table instance
|
|
43
|
+
* @param indexes - The index definitions
|
|
44
|
+
*/
|
|
45
|
+
constructor(table, indexes = {}) {
|
|
46
|
+
this.table = table;
|
|
47
|
+
this.indexes = indexes;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build index attributes for item creation
|
|
51
|
+
*
|
|
52
|
+
* @param item - The item to generate indexes for
|
|
53
|
+
* @param options - Options for building indexes
|
|
54
|
+
* @returns Record of GSI attribute names to their values
|
|
55
|
+
*/
|
|
56
|
+
buildForCreate(item, options = {}) {
|
|
57
|
+
const attributes = {};
|
|
58
|
+
for (const [indexName, indexDef] of Object.entries(this.indexes)) {
|
|
59
|
+
if (options.excludeReadOnly && indexDef.isReadOnly) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const key = indexDef.generateKey(item);
|
|
63
|
+
const gsiConfig = this.table.gsis[indexName];
|
|
64
|
+
if (!gsiConfig) {
|
|
65
|
+
throw new Error(`GSI configuration not found for index: ${indexName}`);
|
|
66
|
+
}
|
|
67
|
+
if (key.pk) {
|
|
68
|
+
attributes[gsiConfig.partitionKey] = key.pk;
|
|
69
|
+
}
|
|
70
|
+
if (key.sk && gsiConfig.sortKey) {
|
|
71
|
+
attributes[gsiConfig.sortKey] = key.sk;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return attributes;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Build index attributes for item updates
|
|
78
|
+
*
|
|
79
|
+
* @param currentData - The current data before update
|
|
80
|
+
* @param updates - The update data
|
|
81
|
+
* @param options - Options for building indexes
|
|
82
|
+
* @returns Record of GSI attribute names to their updated values
|
|
83
|
+
*/
|
|
84
|
+
buildForUpdate(currentData, updates) {
|
|
85
|
+
const attributes = {};
|
|
86
|
+
const updatedItem = { ...currentData, ...updates };
|
|
87
|
+
for (const [indexName, indexDef] of Object.entries(this.indexes)) {
|
|
88
|
+
if (indexDef.isReadOnly) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
let shouldUpdateIndex = false;
|
|
92
|
+
try {
|
|
93
|
+
const currentKey = indexDef.generateKey(currentData);
|
|
94
|
+
const updatedKey = indexDef.generateKey(updatedItem);
|
|
95
|
+
if (currentKey.pk !== updatedKey.pk || currentKey.sk !== updatedKey.sk) {
|
|
96
|
+
shouldUpdateIndex = true;
|
|
50
97
|
}
|
|
51
|
-
|
|
52
|
-
|
|
98
|
+
} catch {
|
|
99
|
+
shouldUpdateIndex = true;
|
|
100
|
+
}
|
|
101
|
+
if (!shouldUpdateIndex) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
let key;
|
|
105
|
+
try {
|
|
106
|
+
key = indexDef.generateKey(updatedItem);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof Error) {
|
|
109
|
+
throw new Error(`Missing attributes: ${error.message}`);
|
|
53
110
|
}
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
{
|
|
57
|
-
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
if (this.hasUndefinedValues(key)) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Missing attributes: Cannot update entity: insufficient data to regenerate index "${indexName}". All attributes required by the index must be provided in the update operation, or the index must be marked as readOnly.`
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
const gsiConfig = this.table.gsis[indexName];
|
|
119
|
+
if (!gsiConfig) {
|
|
120
|
+
throw new Error(`GSI configuration not found for index: ${indexName}`);
|
|
121
|
+
}
|
|
122
|
+
if (key.pk) {
|
|
123
|
+
attributes[gsiConfig.partitionKey] = key.pk;
|
|
124
|
+
}
|
|
125
|
+
if (key.sk && gsiConfig.sortKey) {
|
|
126
|
+
attributes[gsiConfig.sortKey] = key.sk;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return attributes;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Check if a key has undefined values
|
|
133
|
+
*
|
|
134
|
+
* @param key - The index key to check
|
|
135
|
+
* @returns True if the key contains undefined values, false otherwise
|
|
136
|
+
*/
|
|
137
|
+
hasUndefinedValues(key) {
|
|
138
|
+
return (key.pk?.includes("undefined") ?? false) || (key.sk?.includes("undefined") ?? false);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// src/entity/index-utils.ts
|
|
143
|
+
function buildIndexes(dataForKeyGeneration, table, indexes, excludeReadOnly = false) {
|
|
144
|
+
if (!indexes) {
|
|
145
|
+
return {};
|
|
146
|
+
}
|
|
147
|
+
const indexBuilder = new IndexBuilder(table, indexes);
|
|
148
|
+
return indexBuilder.buildForCreate(dataForKeyGeneration, { excludeReadOnly });
|
|
149
|
+
}
|
|
150
|
+
function buildIndexUpdates(currentData, updates, table, indexes) {
|
|
151
|
+
if (!indexes) {
|
|
152
|
+
return {};
|
|
153
|
+
}
|
|
154
|
+
const indexBuilder = new IndexBuilder(table, indexes);
|
|
155
|
+
return indexBuilder.buildForUpdate(currentData, updates);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/entity/entity.ts
|
|
159
|
+
function defineEntity(config) {
|
|
160
|
+
const entityTypeAttributeName = config.settings?.entityTypeAttributeName ?? "entityType";
|
|
161
|
+
const buildIndexes2 = (dataForKeyGeneration, table, excludeReadOnly = false) => {
|
|
162
|
+
return buildIndexes(dataForKeyGeneration, table, config.indexes, excludeReadOnly);
|
|
58
163
|
};
|
|
59
164
|
const wrapMethodWithPreparation = (originalMethod, prepareFn, context) => {
|
|
60
165
|
const wrappedMethod = (...args) => {
|
|
@@ -106,7 +211,7 @@ function defineEntity(config) {
|
|
|
106
211
|
...generateTimestamps(["createdAt", "updatedAt"], validatedData.value)
|
|
107
212
|
};
|
|
108
213
|
const primaryKey = config.primaryKey.generateKey(dataForKeyGeneration);
|
|
109
|
-
const indexes = buildIndexes(dataForKeyGeneration, table);
|
|
214
|
+
const indexes = buildIndexes(dataForKeyGeneration, table, config.indexes, false);
|
|
110
215
|
const validatedItem = {
|
|
111
216
|
...dataForKeyGeneration,
|
|
112
217
|
[entityTypeAttributeName]: config.name,
|
|
@@ -132,7 +237,7 @@ function defineEntity(config) {
|
|
|
132
237
|
...generateTimestamps(["createdAt", "updatedAt"], validationResult.value)
|
|
133
238
|
};
|
|
134
239
|
const primaryKey = config.primaryKey.generateKey(dataForKeyGeneration);
|
|
135
|
-
const indexes = buildIndexes(dataForKeyGeneration, table);
|
|
240
|
+
const indexes = buildIndexes(dataForKeyGeneration, table, config.indexes, false);
|
|
136
241
|
const validatedItem = {
|
|
137
242
|
...dataForKeyGeneration,
|
|
138
243
|
[entityTypeAttributeName]: config.name,
|
|
@@ -174,7 +279,7 @@ function defineEntity(config) {
|
|
|
174
279
|
...generateTimestamps(["createdAt", "updatedAt"], validatedData.value)
|
|
175
280
|
};
|
|
176
281
|
const primaryKey = config.primaryKey.generateKey(dataForKeyGeneration);
|
|
177
|
-
const indexes =
|
|
282
|
+
const indexes = buildIndexes2(dataForKeyGeneration, table, false);
|
|
178
283
|
const validatedItem = {
|
|
179
284
|
[table.partitionKey]: primaryKey.pk,
|
|
180
285
|
...table.sortKey ? { [table.sortKey]: primaryKey.sk } : {},
|
|
@@ -200,7 +305,7 @@ function defineEntity(config) {
|
|
|
200
305
|
...generateTimestamps(["createdAt", "updatedAt"], validationResult.value)
|
|
201
306
|
};
|
|
202
307
|
const primaryKey = config.primaryKey.generateKey(dataForKeyGeneration);
|
|
203
|
-
const indexes = buildIndexes(dataForKeyGeneration, table);
|
|
308
|
+
const indexes = buildIndexes(dataForKeyGeneration, table, config.indexes, false);
|
|
204
309
|
const validatedItem = {
|
|
205
310
|
[table.partitionKey]: primaryKey.pk,
|
|
206
311
|
...table.sortKey ? { [table.sortKey]: primaryKey.sk } : {},
|
|
@@ -234,13 +339,21 @@ function defineEntity(config) {
|
|
|
234
339
|
}
|
|
235
340
|
return createEntityAwarePutBuilder(builder, config.name);
|
|
236
341
|
},
|
|
237
|
-
get: (key) =>
|
|
342
|
+
get: (key) => {
|
|
343
|
+
return createEntityAwareGetBuilder(table.get(config.primaryKey.generateKey(key)), config.name);
|
|
344
|
+
},
|
|
238
345
|
update: (key, data) => {
|
|
239
346
|
const primaryKeyObj = config.primaryKey.generateKey(key);
|
|
240
347
|
const builder = table.update(primaryKeyObj);
|
|
241
348
|
builder.condition(eq(entityTypeAttributeName, config.name));
|
|
242
349
|
const timestamps = generateTimestamps(["updatedAt"], data);
|
|
243
|
-
|
|
350
|
+
const indexUpdates = buildIndexUpdates(
|
|
351
|
+
{ ...key },
|
|
352
|
+
{ ...data, ...timestamps },
|
|
353
|
+
table,
|
|
354
|
+
config.indexes
|
|
355
|
+
);
|
|
356
|
+
builder.set({ ...data, ...timestamps, ...indexUpdates });
|
|
244
357
|
return builder;
|
|
245
358
|
},
|
|
246
359
|
delete: (key) => {
|
|
@@ -311,21 +424,57 @@ function createQueries() {
|
|
|
311
424
|
}
|
|
312
425
|
function createIndex() {
|
|
313
426
|
return {
|
|
314
|
-
input: (schema) =>
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
427
|
+
input: (schema) => {
|
|
428
|
+
const createIndexBuilder = (isReadOnly = false) => ({
|
|
429
|
+
partitionKey: (pkFn) => ({
|
|
430
|
+
sortKey: (skFn) => {
|
|
431
|
+
const index = {
|
|
432
|
+
name: "custom",
|
|
433
|
+
partitionKey: "pk",
|
|
434
|
+
sortKey: "sk",
|
|
435
|
+
isReadOnly,
|
|
436
|
+
generateKey: (item) => {
|
|
437
|
+
const data = schema["~standard"].validate(item);
|
|
438
|
+
if ("issues" in data && data.issues) {
|
|
439
|
+
throw new Error(`Index validation failed: ${data.issues.map((i) => i.message).join(", ")}`);
|
|
440
|
+
}
|
|
441
|
+
const validData = "value" in data ? data.value : item;
|
|
442
|
+
return { pk: pkFn(validData), sk: skFn(validData) };
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
return Object.assign(index, {
|
|
446
|
+
readOnly: (value = false) => ({
|
|
447
|
+
...index,
|
|
448
|
+
isReadOnly: value
|
|
449
|
+
})
|
|
450
|
+
});
|
|
451
|
+
},
|
|
452
|
+
withoutSortKey: () => {
|
|
453
|
+
const index = {
|
|
454
|
+
name: "custom",
|
|
455
|
+
partitionKey: "pk",
|
|
456
|
+
isReadOnly,
|
|
457
|
+
generateKey: (item) => {
|
|
458
|
+
const data = schema["~standard"].validate(item);
|
|
459
|
+
if ("issues" in data && data.issues) {
|
|
460
|
+
throw new Error(`Index validation failed: ${data.issues.map((i) => i.message).join(", ")}`);
|
|
461
|
+
}
|
|
462
|
+
const validData = "value" in data ? data.value : item;
|
|
463
|
+
return { pk: pkFn(validData) };
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
return Object.assign(index, {
|
|
467
|
+
readOnly: (value = true) => ({
|
|
468
|
+
...index,
|
|
469
|
+
isReadOnly: value
|
|
470
|
+
})
|
|
471
|
+
});
|
|
472
|
+
}
|
|
321
473
|
}),
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
})
|
|
327
|
-
})
|
|
328
|
-
})
|
|
474
|
+
readOnly: (value = true) => createIndexBuilder(value)
|
|
475
|
+
});
|
|
476
|
+
return createIndexBuilder(false);
|
|
477
|
+
}
|
|
329
478
|
};
|
|
330
479
|
}
|
|
331
480
|
|