dinah 0.11.1 → 0.12.0
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 +7 -2
- package/dist/index.cjs +97 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +34 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +97 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,13 +99,18 @@ const UserTable = new Table(
|
|
|
99
99
|
|
|
100
100
|
### Using the Repository Class
|
|
101
101
|
|
|
102
|
-
`Repo` is the recommended way to interact with DynamoDB.
|
|
102
|
+
`Repo` is the recommended way to interact with DynamoDB. Use `db.makeRepo` to create a repo inline, with or without configuration:
|
|
103
103
|
|
|
104
104
|
```typescript
|
|
105
105
|
const userRepo = db.makeRepo(UserTable);
|
|
106
|
+
|
|
107
|
+
const userRepo = db.makeRepo(UserTable, {
|
|
108
|
+
defaultPutData: () => ({ createdAt: Date.now() }),
|
|
109
|
+
defaultUpdateData: () => ({ updatedAt: Date.now() }),
|
|
110
|
+
});
|
|
106
111
|
```
|
|
107
112
|
|
|
108
|
-
|
|
113
|
+
To create a named, reusable repo class, use the standalone `makeRepo` (see [Repository Configuration](#repository-configuration)):
|
|
109
114
|
|
|
110
115
|
```typescript
|
|
111
116
|
import { makeRepo } from "dinah";
|
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,25 @@ const require_util = require("./util-D88GS6Gt.cjs");
|
|
|
3
3
|
let _aws_sdk_client_dynamodb = require("@aws-sdk/client-dynamodb");
|
|
4
4
|
let _aws_sdk_lib_dynamodb = require("@aws-sdk/lib-dynamodb");
|
|
5
5
|
_aws_sdk_lib_dynamodb = require_util.__toESM(_aws_sdk_lib_dynamodb, 1);
|
|
6
|
+
//#region src/error.ts
|
|
7
|
+
function dinahErrorMessage(details) {
|
|
8
|
+
switch (details.type) {
|
|
9
|
+
case "NOT_FOUND": return `${details.resource ?? "Item"} not found: ${JSON.stringify(details.key)}`;
|
|
10
|
+
case "CONDITIONAL_CHECK_FAILED": return details.key ? `${details.resource ?? "Item"} condition check failed: ${JSON.stringify(details.key)}` : `${details.resource ?? "Item"} condition check failed`;
|
|
11
|
+
case "VALIDATION": return `Validation error: ${details.message}`;
|
|
12
|
+
case "TRANSACTION_CANCELED": return `Transaction canceled: ${details.reasons.map((r) => r.type).join(", ")}`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
var DinahError = class extends Error {
|
|
16
|
+
details;
|
|
17
|
+
constructor(details, options) {
|
|
18
|
+
super(dinahErrorMessage(details), options);
|
|
19
|
+
this.name = "DinahError";
|
|
20
|
+
this.details = details;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const isDinahError = (err) => err instanceof DinahError;
|
|
24
|
+
//#endregion
|
|
6
25
|
//#region src/expression-builder.ts
|
|
7
26
|
const attrTypes = [
|
|
8
27
|
"S",
|
|
@@ -225,6 +244,13 @@ var Repo = class {
|
|
|
225
244
|
get tableName() {
|
|
226
245
|
return `${this.db.config?.tableNamePrefix ?? ""}${this.table.def.name}`;
|
|
227
246
|
}
|
|
247
|
+
get resourceName() {
|
|
248
|
+
if (this.config.resourceName) return this.config.resourceName;
|
|
249
|
+
const clsName = this.constructor.name;
|
|
250
|
+
if (clsName && clsName !== "Repo") return clsName.replace(/Repo$/i, "") || clsName;
|
|
251
|
+
const t = this.table.def.name;
|
|
252
|
+
return t.charAt(0).toUpperCase() + t.slice(1);
|
|
253
|
+
}
|
|
228
254
|
get defaultPutData() {
|
|
229
255
|
return this.config.defaultPutData?.() ?? {};
|
|
230
256
|
}
|
|
@@ -257,6 +283,7 @@ var Repo = class {
|
|
|
257
283
|
const item = await this.db.getOrThrow({
|
|
258
284
|
table: this.tableName,
|
|
259
285
|
key: this.extractKey(key),
|
|
286
|
+
resource: this.resourceName,
|
|
260
287
|
...options
|
|
261
288
|
});
|
|
262
289
|
return this.applyTransformIfNeeded(item, options);
|
|
@@ -266,6 +293,7 @@ var Repo = class {
|
|
|
266
293
|
const result = await this.db.put({
|
|
267
294
|
table: this.tableName,
|
|
268
295
|
item: itemWithDefaults,
|
|
296
|
+
resource: this.resourceName,
|
|
269
297
|
...options
|
|
270
298
|
});
|
|
271
299
|
return this.applyTransformIfNeeded(result);
|
|
@@ -278,6 +306,7 @@ var Repo = class {
|
|
|
278
306
|
const result = await this.db.update({
|
|
279
307
|
table: this.tableName,
|
|
280
308
|
key: this.extractKey(key),
|
|
309
|
+
resource: this.resourceName,
|
|
281
310
|
update: updateWithDefaults,
|
|
282
311
|
...options
|
|
283
312
|
});
|
|
@@ -296,6 +325,7 @@ var Repo = class {
|
|
|
296
325
|
const item = await this.db.delete({
|
|
297
326
|
table: this.tableName,
|
|
298
327
|
key: this.extractKey(key),
|
|
328
|
+
resource: this.resourceName,
|
|
299
329
|
...options
|
|
300
330
|
});
|
|
301
331
|
return item && this.applyTransformIfNeeded(item);
|
|
@@ -304,6 +334,7 @@ var Repo = class {
|
|
|
304
334
|
const item = await this.db.deleteOrThrow({
|
|
305
335
|
table: this.tableName,
|
|
306
336
|
key: this.extractKey(key),
|
|
337
|
+
resource: this.resourceName,
|
|
307
338
|
...options
|
|
308
339
|
});
|
|
309
340
|
return this.applyTransformIfNeeded(item);
|
|
@@ -409,6 +440,7 @@ var Repo = class {
|
|
|
409
440
|
async batchGetOrThrow(keys, options) {
|
|
410
441
|
const result = await this.db.batchGetOrThrow({ [this.tableName]: {
|
|
411
442
|
keys: keys.map((key) => this.extractKey(key)),
|
|
443
|
+
resource: this.resourceName,
|
|
412
444
|
...options
|
|
413
445
|
} });
|
|
414
446
|
return this.applyTransformsIfNeeded(result[this.tableName] ?? [], options);
|
|
@@ -450,6 +482,7 @@ var Repo = class {
|
|
|
450
482
|
const items = await this.db.trxGetOrThrow(...keys.map((key) => ({
|
|
451
483
|
table: this.tableName,
|
|
452
484
|
key: this.extractKey(key),
|
|
485
|
+
resource: this.resourceName,
|
|
453
486
|
...options
|
|
454
487
|
})));
|
|
455
488
|
return this.applyTransformsIfNeeded(items, options);
|
|
@@ -657,7 +690,11 @@ var Db = class {
|
|
|
657
690
|
}
|
|
658
691
|
async getOrThrow(data) {
|
|
659
692
|
const item = await this.get(data);
|
|
660
|
-
if (!item) throw new
|
|
693
|
+
if (!item) throw new DinahError({
|
|
694
|
+
type: "NOT_FOUND",
|
|
695
|
+
key: data.key,
|
|
696
|
+
resource: data.resource
|
|
697
|
+
});
|
|
661
698
|
return item;
|
|
662
699
|
}
|
|
663
700
|
async put(data) {
|
|
@@ -672,8 +709,16 @@ var Db = class {
|
|
|
672
709
|
ExpressionAttributeNames: exp.attributeNames,
|
|
673
710
|
ExpressionAttributeValues: exp.attributeValues
|
|
674
711
|
});
|
|
675
|
-
|
|
676
|
-
|
|
712
|
+
try {
|
|
713
|
+
const output = await this.client.send(input);
|
|
714
|
+
return data.returnOld ? output.Attributes : item;
|
|
715
|
+
} catch (err) {
|
|
716
|
+
if (err instanceof _aws_sdk_client_dynamodb.ConditionalCheckFailedException) throw new DinahError({
|
|
717
|
+
type: "CONDITIONAL_CHECK_FAILED",
|
|
718
|
+
resource: data.resource
|
|
719
|
+
}, { cause: err });
|
|
720
|
+
throw err;
|
|
721
|
+
}
|
|
677
722
|
}
|
|
678
723
|
async update(data) {
|
|
679
724
|
const exp = new ExpressionBuilder();
|
|
@@ -689,7 +734,16 @@ var Db = class {
|
|
|
689
734
|
ExpressionAttributeNames: exp.attributeNames,
|
|
690
735
|
ExpressionAttributeValues: exp.attributeValues
|
|
691
736
|
});
|
|
692
|
-
|
|
737
|
+
try {
|
|
738
|
+
return (await this.client.send(input)).Attributes;
|
|
739
|
+
} catch (err) {
|
|
740
|
+
if (err instanceof _aws_sdk_client_dynamodb.ConditionalCheckFailedException) throw new DinahError({
|
|
741
|
+
type: "CONDITIONAL_CHECK_FAILED",
|
|
742
|
+
key: data.key,
|
|
743
|
+
resource: data.resource
|
|
744
|
+
}, { cause: err });
|
|
745
|
+
throw err;
|
|
746
|
+
}
|
|
693
747
|
}
|
|
694
748
|
async delete(data) {
|
|
695
749
|
const exp = new ExpressionBuilder();
|
|
@@ -702,11 +756,24 @@ var Db = class {
|
|
|
702
756
|
ExpressionAttributeNames: exp.attributeNames,
|
|
703
757
|
ExpressionAttributeValues: exp.attributeValues
|
|
704
758
|
});
|
|
705
|
-
|
|
759
|
+
try {
|
|
760
|
+
return (await this.client.send(input)).Attributes;
|
|
761
|
+
} catch (err) {
|
|
762
|
+
if (err instanceof _aws_sdk_client_dynamodb.ConditionalCheckFailedException) throw new DinahError({
|
|
763
|
+
type: "CONDITIONAL_CHECK_FAILED",
|
|
764
|
+
key: data.key,
|
|
765
|
+
resource: data.resource
|
|
766
|
+
}, { cause: err });
|
|
767
|
+
throw err;
|
|
768
|
+
}
|
|
706
769
|
}
|
|
707
770
|
async deleteOrThrow(data) {
|
|
708
771
|
const item = await this.delete(data);
|
|
709
|
-
if (!item) throw new
|
|
772
|
+
if (!item) throw new DinahError({
|
|
773
|
+
type: "NOT_FOUND",
|
|
774
|
+
key: data.key,
|
|
775
|
+
resource: data.resource
|
|
776
|
+
});
|
|
710
777
|
return item;
|
|
711
778
|
}
|
|
712
779
|
async *queryPaged(data) {
|
|
@@ -863,7 +930,11 @@ var Db = class {
|
|
|
863
930
|
const { items, unprocessed } = await this.batchGet(data);
|
|
864
931
|
for (const table of Object.keys(data)) {
|
|
865
932
|
if (unprocessed?.[table]) throw new Error(`One or more batch get requests were not processed in "${table}" table.`);
|
|
866
|
-
if (items[table]?.length !== data[table]?.keys?.length) throw new
|
|
933
|
+
if (items[table]?.length !== data[table]?.keys?.length) throw new DinahError({
|
|
934
|
+
type: "NOT_FOUND",
|
|
935
|
+
key: {},
|
|
936
|
+
resource: data[table]?.resource
|
|
937
|
+
});
|
|
867
938
|
}
|
|
868
939
|
return items;
|
|
869
940
|
}
|
|
@@ -983,7 +1054,11 @@ var Db = class {
|
|
|
983
1054
|
}
|
|
984
1055
|
async trxGetOrThrow(...requests) {
|
|
985
1056
|
const items = await this.trxGet(...requests);
|
|
986
|
-
for (let i = 0; i < items.length; i++) if (!items[i]) throw new
|
|
1057
|
+
for (let i = 0; i < items.length; i++) if (!items[i]) throw new DinahError({
|
|
1058
|
+
type: "NOT_FOUND",
|
|
1059
|
+
key: requests[i]?.key ?? {},
|
|
1060
|
+
resource: requests[i]?.resource
|
|
1061
|
+
});
|
|
987
1062
|
return items;
|
|
988
1063
|
}
|
|
989
1064
|
async trxWrite(...requests) {
|
|
@@ -1013,7 +1088,18 @@ var Db = class {
|
|
|
1013
1088
|
} };
|
|
1014
1089
|
});
|
|
1015
1090
|
const input = new _aws_sdk_lib_dynamodb.TransactWriteCommand({ TransactItems: trxItems });
|
|
1016
|
-
|
|
1091
|
+
try {
|
|
1092
|
+
await this.client.send(input);
|
|
1093
|
+
} catch (err) {
|
|
1094
|
+
if (err instanceof _aws_sdk_client_dynamodb.TransactionCanceledException) throw new DinahError({
|
|
1095
|
+
type: "TRANSACTION_CANCELED",
|
|
1096
|
+
reasons: (err.CancellationReasons ?? []).map((r) => ({
|
|
1097
|
+
type: r.Code ?? "Unknown",
|
|
1098
|
+
message: r.Message
|
|
1099
|
+
}))
|
|
1100
|
+
}, { cause: err });
|
|
1101
|
+
throw err;
|
|
1102
|
+
}
|
|
1017
1103
|
}
|
|
1018
1104
|
};
|
|
1019
1105
|
//#endregion
|
|
@@ -1028,10 +1114,12 @@ var Table = class {
|
|
|
1028
1114
|
};
|
|
1029
1115
|
//#endregion
|
|
1030
1116
|
exports.Db = Db;
|
|
1117
|
+
exports.DinahError = DinahError;
|
|
1031
1118
|
exports.Repo = Repo;
|
|
1032
1119
|
exports.Table = Table;
|
|
1033
1120
|
exports.chunk = require_util.chunk;
|
|
1034
1121
|
exports.extractTableDesc = require_util.extractTableDesc;
|
|
1122
|
+
exports.isDinahError = isDinahError;
|
|
1035
1123
|
exports.makeRepo = makeRepo;
|
|
1036
1124
|
exports.removeUndefined = require_util.removeUndefined;
|
|
1037
1125
|
exports.resolveAttrType = require_util.resolveAttrType;
|