@moicky/dynamodb 1.1.0 → 1.1.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/index.js +19 -0
- package/dist/lib/client.d.ts +0 -1
- package/dist/lib/client.js +11 -0
- package/dist/lib/helpers.js +40 -0
- package/dist/operations/delete.js +52 -0
- package/dist/operations/get.js +77 -0
- package/dist/operations/index.js +22 -0
- package/dist/operations/misc.js +34 -0
- package/dist/operations/put.js +45 -0
- package/dist/operations/query.js +44 -0
- package/dist/operations/update.js +37 -0
- package/package.json +9 -12
- package/readme.md +13 -36
- package/dist/built/commonjs/index.js +0 -1
- package/dist/built/esnext/index.js +0 -1
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./operations"), exports);
|
|
18
|
+
__exportStar(require("./lib/client"), exports);
|
|
19
|
+
__exportStar(require("./lib/helpers"), exports);
|
package/dist/lib/client.d.ts
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TableName = exports.client = void 0;
|
|
4
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
5
|
+
exports.client = new client_dynamodb_1.DynamoDBClient({
|
|
6
|
+
region: process.env.AWS_REGION || "eu-central-1",
|
|
7
|
+
});
|
|
8
|
+
exports.TableName = process.env.DYNAMODB_TABLE;
|
|
9
|
+
if (!exports.TableName) {
|
|
10
|
+
throw new Error("Missing DYNAMODB_TABLE environment variable");
|
|
11
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAttributesFromExpression = exports.getAttributeNames = exports.getAttributeValues = exports.splitEvery = exports.stripKey = void 0;
|
|
4
|
+
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
5
|
+
// ----- Configuration -----
|
|
6
|
+
// Since dynamo only accepts key atrtributes which are described in table schema
|
|
7
|
+
// we remove any other attributes from the item if they are present and passed as
|
|
8
|
+
// key parameter to any of the functions below (getItem, updateItem, deleteItem...)
|
|
9
|
+
function stripKey(key) {
|
|
10
|
+
return (0, util_dynamodb_1.marshall)({ PK: key.PK, SK: key.SK });
|
|
11
|
+
}
|
|
12
|
+
exports.stripKey = stripKey;
|
|
13
|
+
function splitEvery(items, limit = 25) {
|
|
14
|
+
const batches = [];
|
|
15
|
+
for (let i = 0; i < items.length; i += limit) {
|
|
16
|
+
batches.push(items.slice(i, i + limit));
|
|
17
|
+
}
|
|
18
|
+
return batches;
|
|
19
|
+
}
|
|
20
|
+
exports.splitEvery = splitEvery;
|
|
21
|
+
function getAttributeValues(key, attributesToGet) {
|
|
22
|
+
return (0, util_dynamodb_1.marshall)((attributesToGet || Object.keys(key)).reduce((acc, keyName) => {
|
|
23
|
+
acc[`:${keyName}`] = key[keyName];
|
|
24
|
+
return acc;
|
|
25
|
+
}, {}));
|
|
26
|
+
}
|
|
27
|
+
exports.getAttributeValues = getAttributeValues;
|
|
28
|
+
function getAttributeNames(key, attributesToGet) {
|
|
29
|
+
return (attributesToGet || Object.keys(key)).reduce((acc, keyName) => {
|
|
30
|
+
acc[`#${keyName}`] = keyName;
|
|
31
|
+
return acc;
|
|
32
|
+
}, {});
|
|
33
|
+
}
|
|
34
|
+
exports.getAttributeNames = getAttributeNames;
|
|
35
|
+
function getAttributesFromExpression(expression, prefix = "#") {
|
|
36
|
+
return (expression
|
|
37
|
+
.match(new RegExp(`${prefix}\\w+`, "g"))
|
|
38
|
+
?.map((attr) => attr.slice(1)) || []);
|
|
39
|
+
}
|
|
40
|
+
exports.getAttributesFromExpression = getAttributesFromExpression;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deleteItems = exports.deleteItem = void 0;
|
|
4
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
5
|
+
const client_1 = require("../lib/client");
|
|
6
|
+
const helpers_1 = require("../lib/helpers");
|
|
7
|
+
async function deleteItem(key, args = {}) {
|
|
8
|
+
return client_1.client.send(new client_dynamodb_1.DeleteItemCommand({
|
|
9
|
+
TableName: client_1.TableName,
|
|
10
|
+
Key: (0, helpers_1.stripKey)(key),
|
|
11
|
+
...args,
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
exports.deleteItem = deleteItem;
|
|
15
|
+
async function deleteItems(keys, args = {}, retry = 0) {
|
|
16
|
+
const uniqueKeys = Object.values(keys.reduce((acc, key) => {
|
|
17
|
+
const strippedKey = (0, helpers_1.stripKey)(key);
|
|
18
|
+
const keyString = JSON.stringify(strippedKey);
|
|
19
|
+
if (!acc[keyString]) {
|
|
20
|
+
acc[keyString] = strippedKey;
|
|
21
|
+
}
|
|
22
|
+
return acc;
|
|
23
|
+
}, {}));
|
|
24
|
+
return new Promise(async (resolve, reject) => {
|
|
25
|
+
const batches = (0, helpers_1.splitEvery)(uniqueKeys);
|
|
26
|
+
if (retry > 3)
|
|
27
|
+
return;
|
|
28
|
+
for (const batch of batches) {
|
|
29
|
+
await client_1.client
|
|
30
|
+
.send(new client_dynamodb_1.BatchWriteItemCommand({
|
|
31
|
+
RequestItems: {
|
|
32
|
+
[client_1.TableName]: batch.map((Key) => ({
|
|
33
|
+
DeleteRequest: {
|
|
34
|
+
Key,
|
|
35
|
+
},
|
|
36
|
+
})),
|
|
37
|
+
},
|
|
38
|
+
...args,
|
|
39
|
+
}))
|
|
40
|
+
.then((res) => {
|
|
41
|
+
if (res?.UnprocessedItems?.[client_1.TableName]?.length) {
|
|
42
|
+
if (retry + 1 > 3)
|
|
43
|
+
return reject(res);
|
|
44
|
+
return deleteItems(res.UnprocessedItems[client_1.TableName], args, retry + 1);
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
.catch(reject);
|
|
48
|
+
}
|
|
49
|
+
resolve();
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
exports.deleteItems = deleteItems;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getAllItems = exports.getItems = exports.getItem = void 0;
|
|
4
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
5
|
+
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
6
|
+
const client_1 = require("../lib/client");
|
|
7
|
+
const helpers_1 = require("../lib/helpers");
|
|
8
|
+
async function getItem(key, args = {}) {
|
|
9
|
+
return client_1.client
|
|
10
|
+
.send(new client_dynamodb_1.GetItemCommand({
|
|
11
|
+
TableName: client_1.TableName,
|
|
12
|
+
Key: (0, helpers_1.stripKey)(key),
|
|
13
|
+
...args,
|
|
14
|
+
}))
|
|
15
|
+
.then((res) => res?.Item && (0, util_dynamodb_1.unmarshall)(res.Item));
|
|
16
|
+
}
|
|
17
|
+
exports.getItem = getItem;
|
|
18
|
+
async function getItems(keys, args = {}, retry = 0) {
|
|
19
|
+
// creates batches of 100 items each and performs batchGet on every batch.
|
|
20
|
+
// also retries up to 3 times if there are unprocessed items (due to size limit of 16MB)
|
|
21
|
+
// returns items in same order as keys (not sorted by default when using batchGet)
|
|
22
|
+
if (retry > 3)
|
|
23
|
+
return [];
|
|
24
|
+
const batchReadLimit = 100;
|
|
25
|
+
// duplicate key entries would cause an error, so we remove them
|
|
26
|
+
const uniqueKeys = Object.values(keys.reduce((acc, key) => {
|
|
27
|
+
const strippedKey = (0, helpers_1.stripKey)(key);
|
|
28
|
+
const keyString = JSON.stringify(strippedKey);
|
|
29
|
+
if (!acc[keyString]) {
|
|
30
|
+
acc[keyString] = strippedKey;
|
|
31
|
+
}
|
|
32
|
+
return acc;
|
|
33
|
+
}, {}));
|
|
34
|
+
const batches = (0, helpers_1.splitEvery)(uniqueKeys, batchReadLimit);
|
|
35
|
+
const results = [];
|
|
36
|
+
if (retry > 2) {
|
|
37
|
+
return results;
|
|
38
|
+
}
|
|
39
|
+
await Promise.all(batches.map(async (batch) => {
|
|
40
|
+
await client_1.client
|
|
41
|
+
.send(new client_dynamodb_1.BatchGetItemCommand({
|
|
42
|
+
RequestItems: {
|
|
43
|
+
[client_1.TableName]: {
|
|
44
|
+
Keys: batch,
|
|
45
|
+
...args,
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
}))
|
|
49
|
+
.then((res) => {
|
|
50
|
+
const unprocessed = res?.UnprocessedKeys?.[client_1.TableName];
|
|
51
|
+
const allItemsFromBatch = res?.Responses?.[client_1.TableName] || [];
|
|
52
|
+
if (unprocessed) {
|
|
53
|
+
return getItems(unprocessed.Keys, args, retry + 1).then((items) => allItemsFromBatch.concat(items));
|
|
54
|
+
}
|
|
55
|
+
return allItemsFromBatch.map((item) => item && (0, util_dynamodb_1.unmarshall)(item));
|
|
56
|
+
})
|
|
57
|
+
.then((items) => results.push(...items));
|
|
58
|
+
}));
|
|
59
|
+
const resultItems = results
|
|
60
|
+
.filter((i) => i)
|
|
61
|
+
.reduce((acc, item) => {
|
|
62
|
+
const keyString = JSON.stringify((0, helpers_1.stripKey)(item));
|
|
63
|
+
acc[keyString] = item;
|
|
64
|
+
return acc;
|
|
65
|
+
}, {});
|
|
66
|
+
return keys.map((key) => resultItems[JSON.stringify((0, helpers_1.stripKey)(key))] || undefined);
|
|
67
|
+
}
|
|
68
|
+
exports.getItems = getItems;
|
|
69
|
+
async function getAllItems(args = {}) {
|
|
70
|
+
return client_1.client
|
|
71
|
+
.send(new client_dynamodb_1.ScanCommand({
|
|
72
|
+
TableName: client_1.TableName,
|
|
73
|
+
...args,
|
|
74
|
+
}))
|
|
75
|
+
.then((res) => res.Items.map((item) => item && (0, util_dynamodb_1.unmarshall)(item)));
|
|
76
|
+
}
|
|
77
|
+
exports.getAllItems = getAllItems;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./delete"), exports);
|
|
18
|
+
__exportStar(require("./get"), exports);
|
|
19
|
+
__exportStar(require("./misc"), exports);
|
|
20
|
+
__exportStar(require("./put"), exports);
|
|
21
|
+
__exportStar(require("./query"), exports);
|
|
22
|
+
__exportStar(require("./update"), exports);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getNewId = exports.itemExists = void 0;
|
|
4
|
+
const get_1 = require("./get");
|
|
5
|
+
const query_1 = require("./query");
|
|
6
|
+
async function itemExists(key, args = {}) {
|
|
7
|
+
const item = await (0, get_1.getItem)(key, args);
|
|
8
|
+
return item !== undefined && item !== null;
|
|
9
|
+
}
|
|
10
|
+
exports.itemExists = itemExists;
|
|
11
|
+
async function getNewId({ PK, SK, length = 8, }) {
|
|
12
|
+
// Assumes that you are using SK as the incrementing ID
|
|
13
|
+
if (!PK) {
|
|
14
|
+
throw new Error("Cannot generate new ID: PK");
|
|
15
|
+
}
|
|
16
|
+
let lastId = "0";
|
|
17
|
+
if (!SK) {
|
|
18
|
+
const lastItem = (await (0, query_1.queryItems)("#PK = :PK", { PK }, { Limit: 1, ScanIndexForward: false }))?.[0];
|
|
19
|
+
const parts = lastItem?.["SK"]?.split("/") || [];
|
|
20
|
+
lastId = parts?.[parts.length - 1] || "0";
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const formattedSK = SK + (!SK.endsWith("/") ? "/" : "");
|
|
24
|
+
const lastItem = (await (0, query_1.queryItems)("#PK = :PK and begins_with(#SK, :SK)", { PK, SK: formattedSK }, { Limit: 1, ScanIndexForward: false }))?.[0];
|
|
25
|
+
const parts = lastItem?.["SK"]?.split("/") || [];
|
|
26
|
+
lastId = parts?.[formattedSK.split("/").length - 1] || "0";
|
|
27
|
+
}
|
|
28
|
+
const newId = parseInt(lastId) + 1 + "";
|
|
29
|
+
const withPadding = newId.padStart(length || 0, "0");
|
|
30
|
+
return SK
|
|
31
|
+
? `${SK}${!SK.endsWith("/") ? "/" : ""}${withPadding}`
|
|
32
|
+
: withPadding;
|
|
33
|
+
}
|
|
34
|
+
exports.getNewId = getNewId;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.putItems = exports.putItem = void 0;
|
|
4
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
5
|
+
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
6
|
+
const client_1 = require("../lib/client");
|
|
7
|
+
const helpers_1 = require("../lib/helpers");
|
|
8
|
+
async function putItem(data, args = {}) {
|
|
9
|
+
if (!Object.keys(data).includes("createdAt")) {
|
|
10
|
+
data.createdAt = Date.now();
|
|
11
|
+
}
|
|
12
|
+
return client_1.client.send(new client_dynamodb_1.PutItemCommand({
|
|
13
|
+
TableName: client_1.TableName,
|
|
14
|
+
Item: (0, util_dynamodb_1.marshall)(data),
|
|
15
|
+
...args,
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
exports.putItem = putItem;
|
|
19
|
+
async function putItems(items, args = {}) {
|
|
20
|
+
return new Promise(async (resolve, reject) => {
|
|
21
|
+
const batches = (0, helpers_1.splitEvery)(items);
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
for (const batch of batches) {
|
|
24
|
+
batch.forEach((item) => {
|
|
25
|
+
if (!Object.keys(item).includes("createdAt")) {
|
|
26
|
+
item.createdAt = now;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
await client_1.client
|
|
30
|
+
.send(new client_dynamodb_1.BatchWriteItemCommand({
|
|
31
|
+
RequestItems: {
|
|
32
|
+
[client_1.TableName]: batch.map((item) => ({
|
|
33
|
+
PutRequest: {
|
|
34
|
+
Item: (0, util_dynamodb_1.marshall)(item),
|
|
35
|
+
},
|
|
36
|
+
})),
|
|
37
|
+
},
|
|
38
|
+
...args,
|
|
39
|
+
}))
|
|
40
|
+
.catch(reject);
|
|
41
|
+
}
|
|
42
|
+
resolve();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
exports.putItems = putItems;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.queryAllItems = exports.queryItems = exports.query = void 0;
|
|
4
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
5
|
+
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
6
|
+
const client_1 = require("../lib/client");
|
|
7
|
+
const helpers_1 = require("../lib/helpers");
|
|
8
|
+
async function query(keyCondition, key, args = {}) {
|
|
9
|
+
return client_1.client.send(new client_dynamodb_1.QueryCommand({
|
|
10
|
+
TableName: client_1.TableName,
|
|
11
|
+
KeyConditionExpression: keyCondition,
|
|
12
|
+
ExpressionAttributeValues: (0, helpers_1.getAttributeValues)(key, [
|
|
13
|
+
...(0, helpers_1.getAttributesFromExpression)(keyCondition, ":"),
|
|
14
|
+
...(0, helpers_1.getAttributesFromExpression)(args?.FilterExpression || "", ":"),
|
|
15
|
+
]),
|
|
16
|
+
ExpressionAttributeNames: (0, helpers_1.getAttributeNames)(key, [
|
|
17
|
+
...(0, helpers_1.getAttributesFromExpression)(keyCondition),
|
|
18
|
+
...(0, helpers_1.getAttributesFromExpression)(args?.FilterExpression || ""),
|
|
19
|
+
]),
|
|
20
|
+
...args,
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
exports.query = query;
|
|
24
|
+
async function queryItems(keyCondition, key, args = {}) {
|
|
25
|
+
return query(keyCondition, key, args).then((res) => (res?.Items || []).map((item) => item && (0, util_dynamodb_1.unmarshall)(item)));
|
|
26
|
+
}
|
|
27
|
+
exports.queryItems = queryItems;
|
|
28
|
+
async function queryAllItems(keyCondition, key, args = {}) {
|
|
29
|
+
let data = await query(keyCondition, key, args);
|
|
30
|
+
while (data.LastEvaluatedKey) {
|
|
31
|
+
if (data.LastEvaluatedKey) {
|
|
32
|
+
let helper = await query(keyCondition, key, {
|
|
33
|
+
...args,
|
|
34
|
+
ExclusiveStartKey: data.LastEvaluatedKey,
|
|
35
|
+
});
|
|
36
|
+
if (helper?.Items && data?.Items) {
|
|
37
|
+
data.Items.push(...helper.Items);
|
|
38
|
+
}
|
|
39
|
+
data && (data.LastEvaluatedKey = helper.LastEvaluatedKey);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return (data?.Items || []).map((item) => item && (0, util_dynamodb_1.unmarshall)(item));
|
|
43
|
+
}
|
|
44
|
+
exports.queryAllItems = queryAllItems;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.removeAttributes = exports.updateItem = void 0;
|
|
4
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
5
|
+
const client_1 = require("../lib/client");
|
|
6
|
+
const helpers_1 = require("../lib/helpers");
|
|
7
|
+
async function updateItem(key, data, args = {}) {
|
|
8
|
+
if (!Object.keys(data).includes("updatedAt")) {
|
|
9
|
+
data.updatedAt = Date.now();
|
|
10
|
+
}
|
|
11
|
+
const UpdateExpression = "SET " +
|
|
12
|
+
Object.keys(data)
|
|
13
|
+
.map((key) => `#${key} = :${key}`)
|
|
14
|
+
.join(", ");
|
|
15
|
+
return client_1.client.send(new client_dynamodb_1.UpdateItemCommand({
|
|
16
|
+
TableName: client_1.TableName,
|
|
17
|
+
Key: (0, helpers_1.stripKey)(key),
|
|
18
|
+
UpdateExpression,
|
|
19
|
+
ExpressionAttributeValues: (0, helpers_1.getAttributeValues)(data),
|
|
20
|
+
ExpressionAttributeNames: (0, helpers_1.getAttributeNames)(data),
|
|
21
|
+
...args,
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
exports.updateItem = updateItem;
|
|
25
|
+
async function removeAttributes(key, attributes) {
|
|
26
|
+
const UpdateExpression = "REMOVE " + attributes.map((att) => `#${att}`).join(", ");
|
|
27
|
+
return client_1.client.send(new client_dynamodb_1.UpdateItemCommand({
|
|
28
|
+
TableName: client_1.TableName,
|
|
29
|
+
Key: (0, helpers_1.stripKey)(key),
|
|
30
|
+
UpdateExpression,
|
|
31
|
+
ExpressionAttributeNames: (0, helpers_1.getAttributeNames)(attributes.reduce((acc, att) => {
|
|
32
|
+
acc[att] = att;
|
|
33
|
+
return acc;
|
|
34
|
+
}, {})),
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
exports.removeAttributes = removeAttributes;
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moicky/dynamodb",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"
|
|
5
|
-
"main": "dist/built/commonjs/index.js",
|
|
6
|
-
"module": "dist/built/esnext/index.js",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"main": "dist/index.js",
|
|
7
5
|
"types": "dist/index.d.ts",
|
|
6
|
+
"description": "Contains a collection of convenience functions for working with AWS DynamoDB",
|
|
8
7
|
"homepage": "https://github.com/Moicky/dynamodb#readme",
|
|
9
8
|
"author": {
|
|
10
9
|
"name": "Moicky",
|
|
@@ -19,22 +18,20 @@
|
|
|
19
18
|
},
|
|
20
19
|
"license": "ISC",
|
|
21
20
|
"scripts": {
|
|
22
|
-
"
|
|
23
|
-
"
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"watch": "tsc -w",
|
|
24
23
|
"test": "jest --runInBand"
|
|
25
24
|
},
|
|
26
25
|
"dependencies": {
|
|
27
26
|
"@aws-sdk/client-dynamodb": "^3.338.0",
|
|
28
|
-
"@aws-sdk/util-dynamodb": "^3.338.0"
|
|
29
|
-
"aws-crt": "^1.15.16"
|
|
27
|
+
"@aws-sdk/util-dynamodb": "^3.338.0"
|
|
30
28
|
},
|
|
31
29
|
"devDependencies": {
|
|
32
30
|
"@types/jest": "^29.5.1",
|
|
33
|
-
"
|
|
34
|
-
"aws-sdk": "^2.1383.0",
|
|
31
|
+
"@types/node": "^20.2.4",
|
|
35
32
|
"dotenv": "^16.0.3",
|
|
36
|
-
"
|
|
37
|
-
"
|
|
33
|
+
"typescript": "^5.0.4",
|
|
34
|
+
"jest": "^29.5.0"
|
|
38
35
|
},
|
|
39
36
|
"keywords": [
|
|
40
37
|
"dynamodb-helpers",
|
package/readme.md
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
# @moicky/dynamodb
|
|
2
2
|
|
|
3
|
-
## Stats
|
|
4
|
-
|
|
5
3
|

|
|
6
|
-

|
|
7
|
-

|
|
5
|
+

|
|
8
6
|

|
|
7
|
+

|
|
9
8
|
|
|
10
9
|
## Description
|
|
11
10
|
|
|
@@ -13,6 +12,7 @@ Contains convenience functions for all major dynamodb operations. Requires very
|
|
|
13
12
|
|
|
14
13
|
- 🎁 Will **automatically marshall and unmarshall** items
|
|
15
14
|
- 📦 Will **group items into batches** to avoid aws limits and improve performance
|
|
15
|
+
- ⏱ Will **automatically** add `createdAt` and `updatedAt` attributes on all items to track their most recent create/update operation timestamp. Example value: `Date.now() -> 1685138436000`
|
|
16
16
|
- 🔄 Will **retry** some operations (getItems, deleteItems) **up to 3 times** on unprocessed items
|
|
17
17
|
- 🔒 When specifying an item using its keySchema, all additional attributes (apart from **PK** and **SK**) will be removed to avoid errors
|
|
18
18
|
- 👻 Will **use placeholders** to avoid colliding with [reserved words](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html) if applicable
|
|
@@ -97,28 +97,20 @@ await getAllItems();
|
|
|
97
97
|
```ts
|
|
98
98
|
import { deleteItem, deleteItems } from "@moicky/dynamodb";
|
|
99
99
|
|
|
100
|
-
// Passing more than just the key is possible, but will be removed to avoid errors
|
|
101
|
-
|
|
102
100
|
// Delete single item
|
|
103
101
|
await deleteItem({
|
|
104
102
|
PK: "User/1",
|
|
105
103
|
SK: "Book/1",
|
|
106
|
-
title: "The Great Gatsby", // additional fields will be removed before sending
|
|
104
|
+
title: "The Great Gatsby", // additional fields will be removed before sending to avoid errors
|
|
107
105
|
author: "F. Scott Fitzgerald",
|
|
108
106
|
released: 1925,
|
|
109
107
|
});
|
|
110
108
|
|
|
111
109
|
// Delete multiple items
|
|
112
|
-
//
|
|
113
|
-
// Will
|
|
110
|
+
// KeySchemas will be grouped into batches of 25 and will be retried up to 3 times if there are unprocessed items
|
|
111
|
+
// Will only delete each keySchema only once, even if it is present multiple times in the array to improve performance
|
|
114
112
|
await deleteItems([
|
|
115
|
-
{
|
|
116
|
-
PK: "User/1",
|
|
117
|
-
SK: "Book/1",
|
|
118
|
-
title: "The Great Gatsby", // additional fields will be removed before sending
|
|
119
|
-
author: "F. Scott Fitzgerald",
|
|
120
|
-
released: 1925,
|
|
121
|
-
},
|
|
113
|
+
{ PK: "User/1", SK: "Book/1" },
|
|
122
114
|
// ... infinite more items (will be grouped into batches of 25 due to aws limit) and retried up to 3 times
|
|
123
115
|
]);
|
|
124
116
|
```
|
|
@@ -128,27 +120,13 @@ await deleteItems([
|
|
|
128
120
|
```ts
|
|
129
121
|
import { updateItem, removeAttributes } from "@moicky/dynamodb";
|
|
130
122
|
|
|
131
|
-
// Passing more than just the key is possible, but will be removed to avoid errors
|
|
132
|
-
|
|
133
123
|
// Update the item and overwrite all supplied fields
|
|
134
124
|
await updateItem(
|
|
135
|
-
{
|
|
136
|
-
PK: "User/1",
|
|
137
|
-
SK: "Book/1",
|
|
138
|
-
title: "The Great Gatsby", // additional fields will be removed before sending
|
|
139
|
-
},
|
|
125
|
+
{ PK: "User/1", SK: "Book/1" },
|
|
140
126
|
{ description: "A book about a rich guy", author: "F. Scott Fitzgerald" }
|
|
141
127
|
);
|
|
142
128
|
|
|
143
|
-
|
|
144
|
-
await removeAttributes(
|
|
145
|
-
{
|
|
146
|
-
PK: "User/1",
|
|
147
|
-
SK: "Book/1",
|
|
148
|
-
title: "The Great Gatsby", // additional fields will be removed before sending
|
|
149
|
-
},
|
|
150
|
-
["description"]
|
|
151
|
-
);
|
|
129
|
+
await removeAttributes({ PK: "User/1", SK: "Book/1" }, ["description"]);
|
|
152
130
|
```
|
|
153
131
|
|
|
154
132
|
### Query Items
|
|
@@ -156,7 +134,7 @@ await removeAttributes(
|
|
|
156
134
|
```ts
|
|
157
135
|
import { query, queryItems, queryAllItems } from "@moicky/dynamodb";
|
|
158
136
|
|
|
159
|
-
// You
|
|
137
|
+
// You HAVE TO use placeholders for the keyCondition & filterExpression:
|
|
160
138
|
// prefix the attributeNames with a hash (#) and the attributeValues with a colon (:)
|
|
161
139
|
|
|
162
140
|
// Query only using keyCondition and retrieve complete response
|
|
@@ -188,7 +166,7 @@ const booksWithFilter = await queryAllItems(
|
|
|
188
166
|
to: 2000,
|
|
189
167
|
},
|
|
190
168
|
// additional args with filterExpression
|
|
191
|
-
{ FilterExpression: "#released BETWEEN :from AND :to" }
|
|
169
|
+
{ FilterExpression: "#released BETWEEN :from AND :to" } // allows to override all args
|
|
192
170
|
);
|
|
193
171
|
```
|
|
194
172
|
|
|
@@ -201,15 +179,14 @@ import { itemExists, getNewId } from "@moicky/dynamodb";
|
|
|
201
179
|
const exists = await itemExists({ PK: "User/1", SK: "Book/1" });
|
|
202
180
|
|
|
203
181
|
// Generate ascending ID
|
|
182
|
+
|
|
204
183
|
// Example Structure 1: PK: "User/1", SK: "{{ ASCENDING_ID }}"
|
|
205
184
|
// Last item: { PK: "User/1", SK: "00000009" }
|
|
206
|
-
|
|
207
185
|
const id1 = await getNewId({ PK: "User/1" });
|
|
208
186
|
console.log(id1); // "00000010"
|
|
209
187
|
|
|
210
188
|
// Example Structure 2: PK: "User/1", SK: "Book/{{ ASCENDING_ID }}"
|
|
211
189
|
// Last item: { PK: "User/1", SK: "Book/00000009" }
|
|
212
|
-
|
|
213
190
|
const id2 = await getNewId({ PK: "User/1", SK: "Book" });
|
|
214
191
|
console.log(id2); // "00000010"
|
|
215
192
|
|