dyno-table 0.0.1 → 0.0.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/README.md +344 -0
- package/dist/index.d.ts +183 -62
- package/dist/index.js +230 -136
- package/package.json +18 -18
- package/readme.md +0 -132
package/dist/index.js
CHANGED
|
@@ -1,34 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
BaseRepository: () => BaseRepository,
|
|
24
|
-
ConditionalCheckFailedError: () => ConditionalCheckFailedError,
|
|
25
|
-
DynamoError: () => DynamoError,
|
|
26
|
-
ExponentialBackoffStrategy: () => ExponentialBackoffStrategy,
|
|
27
|
-
ResourceNotFoundError: () => ResourceNotFoundError,
|
|
28
|
-
Table: () => Table
|
|
29
|
-
});
|
|
30
|
-
module.exports = __toCommonJS(index_exports);
|
|
31
|
-
|
|
32
1
|
// src/builders/expression-builder.ts
|
|
33
2
|
var ExpressionBuilder = class {
|
|
34
3
|
nameCount = 0;
|
|
@@ -98,10 +67,7 @@ var ExpressionBuilder = class {
|
|
|
98
67
|
attributes: this.formatAttributes(attributes)
|
|
99
68
|
};
|
|
100
69
|
}
|
|
101
|
-
formatAttributes({
|
|
102
|
-
names,
|
|
103
|
-
values
|
|
104
|
-
}) {
|
|
70
|
+
formatAttributes({ names, values }) {
|
|
105
71
|
return {
|
|
106
72
|
...Object.keys(names).length && { names },
|
|
107
73
|
...Object.keys(values).length && { values }
|
|
@@ -118,18 +84,9 @@ var ExpressionBuilder = class {
|
|
|
118
84
|
const skName = this.generateAlias("name", "sk");
|
|
119
85
|
attributes.names[skName] = indexConfig.skName;
|
|
120
86
|
if (typeof key.sk === "string") {
|
|
121
|
-
conditions.push(
|
|
122
|
-
`${skName} = ${this.addValue(attributes, key.sk, "sk")}`
|
|
123
|
-
);
|
|
87
|
+
conditions.push(`${skName} = ${this.addValue(attributes, key.sk, "sk")}`);
|
|
124
88
|
} else {
|
|
125
|
-
conditions.push(
|
|
126
|
-
this.buildComparison(
|
|
127
|
-
skName,
|
|
128
|
-
key.sk.operator,
|
|
129
|
-
key.sk.value,
|
|
130
|
-
attributes
|
|
131
|
-
)
|
|
132
|
-
);
|
|
89
|
+
conditions.push(this.buildComparison(skName, key.sk.operator, key.sk.value, attributes));
|
|
133
90
|
}
|
|
134
91
|
}
|
|
135
92
|
return {
|
|
@@ -192,6 +149,39 @@ var OperationBuilder = class {
|
|
|
192
149
|
whereIn(field, values) {
|
|
193
150
|
return this.where(field, "IN", values);
|
|
194
151
|
}
|
|
152
|
+
whereLessThan(field, value) {
|
|
153
|
+
return this.where(field, "<", value);
|
|
154
|
+
}
|
|
155
|
+
whereLessThanOrEqual(field, value) {
|
|
156
|
+
return this.where(field, "<=", value);
|
|
157
|
+
}
|
|
158
|
+
whereGreaterThan(field, value) {
|
|
159
|
+
return this.where(field, ">", value);
|
|
160
|
+
}
|
|
161
|
+
whereGreaterThanOrEqual(field, value) {
|
|
162
|
+
return this.where(field, ">=", value);
|
|
163
|
+
}
|
|
164
|
+
whereNotEqual(field, value) {
|
|
165
|
+
return this.where(field, "<>", value);
|
|
166
|
+
}
|
|
167
|
+
whereBeginsWith(field, value) {
|
|
168
|
+
return this.where(field, "begins_with", value);
|
|
169
|
+
}
|
|
170
|
+
whereContains(field, value) {
|
|
171
|
+
return this.where(field, "contains", value);
|
|
172
|
+
}
|
|
173
|
+
whereNotContains(field, value) {
|
|
174
|
+
this.conditions.push({ field, operator: "not_contains", value });
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
whereAttributeType(field, value) {
|
|
178
|
+
this.conditions.push({ field, operator: "attribute_type", value });
|
|
179
|
+
return this;
|
|
180
|
+
}
|
|
181
|
+
whereSize(field, value) {
|
|
182
|
+
this.conditions.push({ field, operator: "size", value });
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
195
185
|
buildConditionExpression() {
|
|
196
186
|
return this.expressionBuilder.createExpression(this.conditions);
|
|
197
187
|
}
|
|
@@ -201,8 +191,17 @@ var OperationBuilder = class {
|
|
|
201
191
|
var PutBuilder = class extends OperationBuilder {
|
|
202
192
|
constructor(item, expressionBuilder, onBuild) {
|
|
203
193
|
super(expressionBuilder);
|
|
204
|
-
this.item = item;
|
|
205
194
|
this.onBuild = onBuild;
|
|
195
|
+
this.item = item;
|
|
196
|
+
}
|
|
197
|
+
item;
|
|
198
|
+
set(field, value) {
|
|
199
|
+
this.item[field] = value;
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
setMany(attributes) {
|
|
203
|
+
this.item = { ...this.item, ...attributes };
|
|
204
|
+
return this;
|
|
206
205
|
}
|
|
207
206
|
build() {
|
|
208
207
|
const { expression, attributes } = this.buildConditionExpression();
|
|
@@ -216,6 +215,11 @@ var PutBuilder = class extends OperationBuilder {
|
|
|
216
215
|
} : void 0
|
|
217
216
|
};
|
|
218
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Runs the put operation to insert the provided attributes into the table.
|
|
220
|
+
*
|
|
221
|
+
* @returns The provided attributes. This does not load the model from the DB after insert
|
|
222
|
+
*/
|
|
219
223
|
async execute() {
|
|
220
224
|
return this.onBuild(this.build());
|
|
221
225
|
}
|
|
@@ -241,10 +245,7 @@ var QueryBuilder = class extends OperationBuilder {
|
|
|
241
245
|
}
|
|
242
246
|
build() {
|
|
243
247
|
const filter = this.buildConditionExpression();
|
|
244
|
-
const keyCondition = this.expressionBuilder.buildKeyCondition(
|
|
245
|
-
this.key,
|
|
246
|
-
this.indexConfig
|
|
247
|
-
);
|
|
248
|
+
const keyCondition = this.expressionBuilder.buildKeyCondition(this.key, this.indexConfig);
|
|
248
249
|
return {
|
|
249
250
|
type: "query",
|
|
250
251
|
keyCondition: {
|
|
@@ -278,8 +279,8 @@ var UpdateBuilder = class extends OperationBuilder {
|
|
|
278
279
|
this.updates[field] = value;
|
|
279
280
|
return this;
|
|
280
281
|
}
|
|
281
|
-
setMany(
|
|
282
|
-
this.updates = { ...this.updates, ...
|
|
282
|
+
setMany(attributes) {
|
|
283
|
+
this.updates = { ...this.updates, ...attributes };
|
|
283
284
|
return this;
|
|
284
285
|
}
|
|
285
286
|
remove(...fields) {
|
|
@@ -351,10 +352,7 @@ function translateExpression(expression, attributes) {
|
|
|
351
352
|
}
|
|
352
353
|
if (attributes.values) {
|
|
353
354
|
for (const [alias, value] of Object.entries(attributes.values)) {
|
|
354
|
-
translated = translated.replace(
|
|
355
|
-
new RegExp(alias, "g"),
|
|
356
|
-
typeof value === "string" ? `"${value}"` : String(value)
|
|
357
|
-
);
|
|
355
|
+
translated = translated.replace(new RegExp(alias, "g"), typeof value === "string" ? `"${value}"` : String(value));
|
|
358
356
|
}
|
|
359
357
|
}
|
|
360
358
|
return translated;
|
|
@@ -372,28 +370,20 @@ Key: ${JSON.stringify(context.key, null, 2)}`);
|
|
|
372
370
|
if (context.expression) {
|
|
373
371
|
const { condition, update, filter, keyCondition } = context.expression;
|
|
374
372
|
if (condition) {
|
|
375
|
-
parts.push(
|
|
376
|
-
|
|
377
|
-
Condition: ${translateExpression(condition, context.attributes)}`
|
|
378
|
-
);
|
|
373
|
+
parts.push(`
|
|
374
|
+
Condition: ${translateExpression(condition, context.attributes)}`);
|
|
379
375
|
}
|
|
380
376
|
if (update) {
|
|
381
|
-
parts.push(
|
|
382
|
-
|
|
383
|
-
Update: ${translateExpression(update, context.attributes)}`
|
|
384
|
-
);
|
|
377
|
+
parts.push(`
|
|
378
|
+
Update: ${translateExpression(update, context.attributes)}`);
|
|
385
379
|
}
|
|
386
380
|
if (filter) {
|
|
387
|
-
parts.push(
|
|
388
|
-
|
|
389
|
-
Filter: ${translateExpression(filter, context.attributes)}`
|
|
390
|
-
);
|
|
381
|
+
parts.push(`
|
|
382
|
+
Filter: ${translateExpression(filter, context.attributes)}`);
|
|
391
383
|
}
|
|
392
384
|
if (keyCondition) {
|
|
393
|
-
parts.push(
|
|
394
|
-
|
|
395
|
-
Key Condition: ${translateExpression(keyCondition, context.attributes)}`
|
|
396
|
-
);
|
|
385
|
+
parts.push(`
|
|
386
|
+
Key Condition: ${translateExpression(keyCondition, context.attributes)}`);
|
|
397
387
|
}
|
|
398
388
|
}
|
|
399
389
|
parts.push(`
|
|
@@ -682,7 +672,10 @@ var DynamoService = class {
|
|
|
682
672
|
async put(options) {
|
|
683
673
|
try {
|
|
684
674
|
const params = this.converter.toPutCommand(options);
|
|
685
|
-
return await this.withRetry(() =>
|
|
675
|
+
return await this.withRetry(async () => {
|
|
676
|
+
await this.client.put(params);
|
|
677
|
+
return options.item;
|
|
678
|
+
});
|
|
686
679
|
} catch (error) {
|
|
687
680
|
handleDynamoError(error, {
|
|
688
681
|
operation: "PUT",
|
|
@@ -772,9 +765,7 @@ var DynamoService = class {
|
|
|
772
765
|
async batchWrite(items) {
|
|
773
766
|
try {
|
|
774
767
|
const chunks = this.chunkArray(items, BATCH_WRITE_LIMIT);
|
|
775
|
-
return await Promise.all(
|
|
776
|
-
chunks.map((chunk) => this.processBatchWrite(chunk))
|
|
777
|
-
);
|
|
768
|
+
return await Promise.all(chunks.map((chunk) => this.processBatchWrite(chunk)));
|
|
778
769
|
} catch (error) {
|
|
779
770
|
handleDynamoError(error, {
|
|
780
771
|
operation: "BATCH_WRITE",
|
|
@@ -784,9 +775,7 @@ var DynamoService = class {
|
|
|
784
775
|
}
|
|
785
776
|
async transactWrite(items) {
|
|
786
777
|
if (items.length > TRANSACTION_LIMIT) {
|
|
787
|
-
throw new Error(
|
|
788
|
-
`Transaction limit exceeded. Maximum is ${TRANSACTION_LIMIT} items, got ${items.length}`
|
|
789
|
-
);
|
|
778
|
+
throw new Error(`Transaction limit exceeded. Maximum is ${TRANSACTION_LIMIT} items, got ${items.length}`);
|
|
790
779
|
}
|
|
791
780
|
try {
|
|
792
781
|
const params = this.converter.toTransactWriteCommand(items);
|
|
@@ -823,10 +812,9 @@ var DynamoService = class {
|
|
|
823
812
|
const processUnprocessedItems = async (unprocessedItems2) => {
|
|
824
813
|
const params2 = this.converter.toBatchWriteCommand(unprocessedItems2);
|
|
825
814
|
const result = await this.client.batchWrite(params2);
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
);
|
|
815
|
+
const outstandingItems = result.UnprocessedItems?.[this.tableName];
|
|
816
|
+
if (outstandingItems && outstandingItems.length > 0) {
|
|
817
|
+
const remainingItems = this.converter.fromBatchWriteResponse(outstandingItems);
|
|
830
818
|
throw {
|
|
831
819
|
name: "UnprocessedItemsError",
|
|
832
820
|
unprocessedItems: remainingItems
|
|
@@ -836,12 +824,11 @@ var DynamoService = class {
|
|
|
836
824
|
};
|
|
837
825
|
const params = this.converter.toBatchWriteCommand(items);
|
|
838
826
|
const initialResult = await this.client.batchWrite(params);
|
|
839
|
-
|
|
827
|
+
const rawUnprocessedItems = initialResult.UnprocessedItems?.[this.tableName];
|
|
828
|
+
if (!rawUnprocessedItems || rawUnprocessedItems.length === 0) {
|
|
840
829
|
return initialResult;
|
|
841
830
|
}
|
|
842
|
-
const unprocessedItems = this.converter.fromBatchWriteResponse(
|
|
843
|
-
initialResult.UnprocessedItems[this.tableName]
|
|
844
|
-
);
|
|
831
|
+
const unprocessedItems = this.converter.fromBatchWriteResponse(rawUnprocessedItems);
|
|
845
832
|
return this.withRetry(() => processUnprocessedItems(unprocessedItems));
|
|
846
833
|
}
|
|
847
834
|
async withRetry(operation, strategy = new ExponentialBackoffStrategy()) {
|
|
@@ -853,9 +840,7 @@ var DynamoService = class {
|
|
|
853
840
|
if (!strategy.shouldRetry(error, attempt)) {
|
|
854
841
|
throw error;
|
|
855
842
|
}
|
|
856
|
-
await new Promise(
|
|
857
|
-
(resolve) => setTimeout(resolve, strategy.getDelay(attempt))
|
|
858
|
-
);
|
|
843
|
+
await new Promise((resolve) => setTimeout(resolve, strategy.getDelay(attempt)));
|
|
859
844
|
attempt++;
|
|
860
845
|
}
|
|
861
846
|
}
|
|
@@ -868,6 +853,46 @@ var DynamoService = class {
|
|
|
868
853
|
}
|
|
869
854
|
};
|
|
870
855
|
|
|
856
|
+
// src/builders/scan-builder.ts
|
|
857
|
+
var ScanBuilder = class extends OperationBuilder {
|
|
858
|
+
constructor(expressionBuilder, onBuild) {
|
|
859
|
+
super(expressionBuilder);
|
|
860
|
+
this.onBuild = onBuild;
|
|
861
|
+
}
|
|
862
|
+
limitValue;
|
|
863
|
+
indexNameValue;
|
|
864
|
+
pageKeyValue;
|
|
865
|
+
limit(value) {
|
|
866
|
+
this.limitValue = value;
|
|
867
|
+
return this;
|
|
868
|
+
}
|
|
869
|
+
useIndex(indexName) {
|
|
870
|
+
this.indexNameValue = indexName;
|
|
871
|
+
return this;
|
|
872
|
+
}
|
|
873
|
+
startKey(key) {
|
|
874
|
+
this.pageKeyValue = key;
|
|
875
|
+
return this;
|
|
876
|
+
}
|
|
877
|
+
build() {
|
|
878
|
+
const filter = this.buildConditionExpression();
|
|
879
|
+
return {
|
|
880
|
+
type: "scan",
|
|
881
|
+
filter: filter.expression ? {
|
|
882
|
+
expression: filter.expression,
|
|
883
|
+
names: filter.attributes.names,
|
|
884
|
+
values: filter.attributes.values
|
|
885
|
+
} : void 0,
|
|
886
|
+
limit: this.limitValue,
|
|
887
|
+
pageKey: this.pageKeyValue,
|
|
888
|
+
indexName: this.indexNameValue
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
async execute() {
|
|
892
|
+
return this.onBuild(this.build());
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
|
|
871
896
|
// src/table.ts
|
|
872
897
|
var Table = class {
|
|
873
898
|
dynamoService;
|
|
@@ -893,18 +918,10 @@ var Table = class {
|
|
|
893
918
|
throw new Error(`Index ${indexName} does not exist`);
|
|
894
919
|
}
|
|
895
920
|
put(item) {
|
|
896
|
-
return new PutBuilder(
|
|
897
|
-
item,
|
|
898
|
-
this.expressionBuilder,
|
|
899
|
-
(operation) => this.executeOperation(operation)
|
|
900
|
-
);
|
|
921
|
+
return new PutBuilder(item, this.expressionBuilder, (operation) => this.executeOperation(operation));
|
|
901
922
|
}
|
|
902
923
|
update(key, data) {
|
|
903
|
-
const builder = new UpdateBuilder(
|
|
904
|
-
key,
|
|
905
|
-
this.expressionBuilder,
|
|
906
|
-
(operation) => this.executeOperation(operation)
|
|
907
|
-
);
|
|
924
|
+
const builder = new UpdateBuilder(key, this.expressionBuilder, (operation) => this.executeOperation(operation));
|
|
908
925
|
if (data) {
|
|
909
926
|
builder.setMany(data);
|
|
910
927
|
}
|
|
@@ -931,22 +948,8 @@ var Table = class {
|
|
|
931
948
|
};
|
|
932
949
|
return this.executeOperation(operation);
|
|
933
950
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
if (filters?.length) {
|
|
937
|
-
const filterResult = this.expressionBuilder.createExpression(filters);
|
|
938
|
-
filter = {
|
|
939
|
-
expression: filterResult.expression,
|
|
940
|
-
names: filterResult.attributes.names,
|
|
941
|
-
values: filterResult.attributes.values
|
|
942
|
-
};
|
|
943
|
-
}
|
|
944
|
-
return this.dynamoService.scan({
|
|
945
|
-
filter,
|
|
946
|
-
limit: options?.limit,
|
|
947
|
-
pageKey: options?.pageKey,
|
|
948
|
-
indexName: options?.indexName
|
|
949
|
-
});
|
|
951
|
+
scan() {
|
|
952
|
+
return new ScanBuilder(this.expressionBuilder, (operation) => this.executeOperation(operation));
|
|
950
953
|
}
|
|
951
954
|
async batchWrite(operations) {
|
|
952
955
|
const batchOperation = {
|
|
@@ -996,6 +999,13 @@ var Table = class {
|
|
|
996
999
|
return this.dynamoService.batchWrite(operation.operations);
|
|
997
1000
|
case "transactWrite":
|
|
998
1001
|
return this.dynamoService.transactWrite(operation.operations);
|
|
1002
|
+
case "scan":
|
|
1003
|
+
return this.dynamoService.scan({
|
|
1004
|
+
filter: operation.filter,
|
|
1005
|
+
limit: operation.limit,
|
|
1006
|
+
pageKey: operation.pageKey,
|
|
1007
|
+
indexName: operation.indexName
|
|
1008
|
+
});
|
|
999
1009
|
default:
|
|
1000
1010
|
throw new Error("Unknown operation type");
|
|
1001
1011
|
}
|
|
@@ -1025,59 +1035,143 @@ var Table = class {
|
|
|
1025
1035
|
|
|
1026
1036
|
// src/repository/base-repository.ts
|
|
1027
1037
|
var BaseRepository = class {
|
|
1028
|
-
constructor(table
|
|
1038
|
+
constructor(table) {
|
|
1029
1039
|
this.table = table;
|
|
1030
|
-
this.schema = schema;
|
|
1031
1040
|
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Hook method called before inserting a record.
|
|
1043
|
+
* Subclasses can override this method to modify the data before insertion.
|
|
1044
|
+
* @param data - The record data.
|
|
1045
|
+
* @returns The modified record data.
|
|
1046
|
+
*/
|
|
1032
1047
|
beforeInsert(data) {
|
|
1033
1048
|
return data;
|
|
1034
1049
|
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Hook method called before updating a record.
|
|
1052
|
+
* Subclasses can override this method to modify the data before updating.
|
|
1053
|
+
* @param data - The partial record data to be updated.
|
|
1054
|
+
* @returns The modified partial record data.
|
|
1055
|
+
*/
|
|
1035
1056
|
beforeUpdate(data) {
|
|
1036
1057
|
return data;
|
|
1037
1058
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1059
|
+
/**
|
|
1060
|
+
* Checks if a record exists in the table.
|
|
1061
|
+
* @param key - The primary key of the record.
|
|
1062
|
+
* @returns A promise that resolves to true if the record exists, false otherwise.
|
|
1063
|
+
*/
|
|
1064
|
+
async exists(key) {
|
|
1065
|
+
const item = await this.table.get(key);
|
|
1066
|
+
return item !== null;
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Type guard to check if the value is a primary key.
|
|
1070
|
+
* @param value - The value to check.
|
|
1071
|
+
* @returns True if the value is a primary key, false otherwise.
|
|
1072
|
+
*/
|
|
1073
|
+
isPrimaryKey(value) {
|
|
1074
|
+
return "pk" in value && typeof value.pk === "string";
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Creates a new record in the table.
|
|
1078
|
+
* @param data - The record data.
|
|
1079
|
+
* @returns A PutBuilder instance to execute the put operation.
|
|
1080
|
+
*/
|
|
1081
|
+
create(data) {
|
|
1082
|
+
const key = this.createPrimaryKey(data);
|
|
1041
1083
|
const item = {
|
|
1042
|
-
...
|
|
1084
|
+
...data,
|
|
1043
1085
|
...key
|
|
1044
1086
|
};
|
|
1045
1087
|
const indexConfig = this.table.getIndexConfig();
|
|
1046
|
-
|
|
1047
|
-
|
|
1088
|
+
const builder = this.table.put(item).set(this.getTypeAttributeName(), this.getType()).whereNotExists(indexConfig.pkName);
|
|
1089
|
+
if (indexConfig.skName) {
|
|
1090
|
+
builder.whereNotExists(indexConfig.skName);
|
|
1091
|
+
}
|
|
1092
|
+
return builder;
|
|
1048
1093
|
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Updates an existing record in the table.
|
|
1096
|
+
* @param key - The primary key of the record.
|
|
1097
|
+
* @param updates - The partial record data to be updated.
|
|
1098
|
+
* @returns A promise that resolves to the updated record or null if the record does not exist.
|
|
1099
|
+
*/
|
|
1049
1100
|
async update(key, updates) {
|
|
1050
|
-
const
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1101
|
+
const processed = this.beforeUpdate(updates);
|
|
1102
|
+
const updateData = {
|
|
1103
|
+
...processed,
|
|
1104
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1105
|
+
};
|
|
1106
|
+
const result = await this.table.update(key).setMany(updateData).execute();
|
|
1107
|
+
if (!result.Attributes) return null;
|
|
1108
|
+
return this.findOne(key);
|
|
1053
1109
|
}
|
|
1054
|
-
|
|
1110
|
+
/**
|
|
1111
|
+
* Upserts (inserts or updates) a record in the table.
|
|
1112
|
+
* @param data - The record data.
|
|
1113
|
+
* @returns A PutBuilder instance to execute the put operation.
|
|
1114
|
+
*/
|
|
1115
|
+
upsert(data) {
|
|
1116
|
+
const key = this.createPrimaryKey(data);
|
|
1117
|
+
return this.table.put({
|
|
1118
|
+
...data,
|
|
1119
|
+
...key
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Deletes a record from the table.
|
|
1124
|
+
* @param keyOrDTO - The primary key or the record data.
|
|
1125
|
+
* @returns A promise that resolves when the record is deleted.
|
|
1126
|
+
*/
|
|
1127
|
+
async delete(keyOrDTO) {
|
|
1128
|
+
if (this.isPrimaryKey(keyOrDTO)) {
|
|
1129
|
+
this.table.delete(keyOrDTO);
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
const key = this.createPrimaryKey(keyOrDTO);
|
|
1055
1133
|
await this.table.delete(key);
|
|
1056
1134
|
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Finds a single record by its primary key.
|
|
1137
|
+
* @param key - The primary key of the record.
|
|
1138
|
+
* @returns A promise that resolves to the record or null if the record does not exist.
|
|
1139
|
+
*/
|
|
1057
1140
|
async findOne(key) {
|
|
1058
|
-
const
|
|
1141
|
+
const results = await this.table.query(key).whereEquals(this.getTypeAttributeName(), this.getType()).limit(1).execute();
|
|
1142
|
+
const item = results.Items?.[0];
|
|
1059
1143
|
if (!item) {
|
|
1060
1144
|
return null;
|
|
1061
1145
|
}
|
|
1062
|
-
return
|
|
1146
|
+
return item;
|
|
1063
1147
|
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Finds a single record by its primary key or throws an error if the record does not exist.
|
|
1150
|
+
* @param key - The primary key of the record.
|
|
1151
|
+
* @returns A promise that resolves to the record.
|
|
1152
|
+
* @throws An error if the record does not exist.
|
|
1153
|
+
*/
|
|
1064
1154
|
async findOrFail(key) {
|
|
1065
1155
|
const result = await this.findOne(key);
|
|
1066
1156
|
if (!result) {
|
|
1067
1157
|
throw new Error("Item not found");
|
|
1068
1158
|
}
|
|
1069
|
-
return
|
|
1159
|
+
return result;
|
|
1070
1160
|
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Creates a query builder for querying records by their primary key.
|
|
1163
|
+
* @param key - The primary key of the record.
|
|
1164
|
+
* @returns A QueryBuilder instance to build and execute the query.
|
|
1165
|
+
*/
|
|
1071
1166
|
query(key) {
|
|
1072
|
-
return this.table.query(key).
|
|
1167
|
+
return this.table.query(key).whereEquals(this.getTypeAttributeName(), this.getType());
|
|
1073
1168
|
}
|
|
1074
1169
|
};
|
|
1075
|
-
|
|
1076
|
-
0 && (module.exports = {
|
|
1170
|
+
export {
|
|
1077
1171
|
BaseRepository,
|
|
1078
1172
|
ConditionalCheckFailedError,
|
|
1079
1173
|
DynamoError,
|
|
1080
1174
|
ExponentialBackoffStrategy,
|
|
1081
1175
|
ResourceNotFoundError,
|
|
1082
1176
|
Table
|
|
1083
|
-
}
|
|
1177
|
+
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dyno-table",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "A TypeScript library to simplify working with DynamoDB",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
|
-
"type": "
|
|
7
|
+
"type": "module",
|
|
8
8
|
"exports": {
|
|
9
9
|
".": {
|
|
10
10
|
"import": "./dist/index.mjs",
|
|
11
11
|
"require": "./dist/index.js"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
16
|
+
"clean": "rm -rf dist",
|
|
17
|
+
"test": "vitest",
|
|
18
|
+
"test:int": "vitest --config vitest.integration.ts",
|
|
19
|
+
"lint": "biome lint",
|
|
20
|
+
"check-types": "tsc --noEmit",
|
|
21
|
+
"ddb:start": "docker compose up -d dynamodb"
|
|
22
|
+
},
|
|
14
23
|
"keywords": [
|
|
15
24
|
"dynamodb",
|
|
16
25
|
"aws",
|
|
@@ -24,28 +33,19 @@
|
|
|
24
33
|
"url": "git+https://github.com/Kysumi/dyno-table.git"
|
|
25
34
|
},
|
|
26
35
|
"devDependencies": {
|
|
36
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
27
37
|
"@biomejs/biome": "1.9.4",
|
|
28
38
|
"@types/node": "^20.0.0",
|
|
29
|
-
"typescript": "^5.0.0",
|
|
30
|
-
"vitest": "^2.1.8",
|
|
31
39
|
"rimraf": "^5.0.0",
|
|
32
|
-
"tsup": "^8.0.0"
|
|
40
|
+
"tsup": "^8.0.0",
|
|
41
|
+
"typescript": "^5.0.0",
|
|
42
|
+
"vitest": "^2.1.8"
|
|
33
43
|
},
|
|
34
44
|
"peerDependencies": {
|
|
35
45
|
"@aws-sdk/client-dynamodb": "^3.0.0",
|
|
36
|
-
"@aws-sdk/lib-dynamodb": "^3.0.0"
|
|
37
|
-
"zod": "^3.0.0"
|
|
46
|
+
"@aws-sdk/lib-dynamodb": "^3.0.0"
|
|
38
47
|
},
|
|
39
48
|
"files": [
|
|
40
49
|
"dist"
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
44
|
-
"clean": "rm -rf dist",
|
|
45
|
-
"test": "vitest",
|
|
46
|
-
"test:int": "vitest --config vitest.integration.ts",
|
|
47
|
-
"lint": "biome lint",
|
|
48
|
-
"check-types": "tsc --noEmit",
|
|
49
|
-
"ddb:start": "docker compose up -d dynamodb"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
50
|
+
]
|
|
51
|
+
}
|