@moicky/dynamodb 1.1.1 → 1.1.3

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.
@@ -1,4 +1,4 @@
1
1
  import { BatchGetItemCommandInput, GetItemCommandInput, ScanCommandInput } from "@aws-sdk/client-dynamodb";
2
2
  export declare function getItem(key: any, args?: Partial<GetItemCommandInput>): Promise<Record<string, any>>;
3
- export declare function getItems(keys: any[], args?: Partial<BatchGetItemCommandInput>, retry?: number): Promise<Record<string, any> | Record<string, any>[]>;
3
+ export declare function getItems(keys: any[], args?: Partial<BatchGetItemCommandInput>, retry?: number): Promise<Record<string, any>[]>;
4
4
  export declare function getAllItems(args?: Partial<ScanCommandInput>): Promise<Record<string, any>[]>;
@@ -27,8 +27,6 @@ async function getNewId({ PK, SK, length = 8, }) {
27
27
  }
28
28
  const newId = parseInt(lastId) + 1 + "";
29
29
  const withPadding = newId.padStart(length || 0, "0");
30
- return SK
31
- ? `${SK}${!SK.endsWith("/") ? "/" : ""}${withPadding}`
32
- : withPadding;
30
+ return withPadding;
33
31
  }
34
32
  exports.getNewId = getNewId;
@@ -1,3 +1,3 @@
1
1
  import { UpdateItemCommandInput, UpdateItemCommandOutput } from "@aws-sdk/client-dynamodb";
2
- export declare function updateItem(key: any, data: any, args?: Partial<UpdateItemCommandInput>): Promise<UpdateItemCommandOutput>;
2
+ export declare function updateItem(key: any, data: any, args?: Partial<UpdateItemCommandInput>): Promise<undefined | Record<string, any>>;
3
3
  export declare function removeAttributes(key: any, attributes: string[]): Promise<UpdateItemCommandOutput>;
@@ -4,22 +4,31 @@ exports.removeAttributes = exports.updateItem = void 0;
4
4
  const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
5
5
  const client_1 = require("../lib/client");
6
6
  const helpers_1 = require("../lib/helpers");
7
+ const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
7
8
  async function updateItem(key, data, args = {}) {
8
9
  if (!Object.keys(data).includes("updatedAt")) {
9
10
  data.updatedAt = Date.now();
10
11
  }
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({
12
+ const valuesInCondition = (0, helpers_1.getAttributesFromExpression)(args?.ConditionExpression || "", ":");
13
+ const namesInCondition = (0, helpers_1.getAttributesFromExpression)(args?.ConditionExpression || "");
14
+ const attributesToUpdate = Object.keys(data).filter((key) => !valuesInCondition.includes(key));
15
+ const UpdateExpression = "SET " + attributesToUpdate.map((key) => `#${key} = :${key}`).join(", ");
16
+ return client_1.client
17
+ .send(new client_dynamodb_1.UpdateItemCommand({
16
18
  TableName: client_1.TableName,
17
19
  Key: (0, helpers_1.stripKey)(key),
18
20
  UpdateExpression,
19
- ExpressionAttributeValues: (0, helpers_1.getAttributeValues)(data),
20
- ExpressionAttributeNames: (0, helpers_1.getAttributeNames)(data),
21
+ ExpressionAttributeValues: (0, helpers_1.getAttributeValues)(data, [
22
+ ...attributesToUpdate,
23
+ ...valuesInCondition,
24
+ ]),
25
+ ExpressionAttributeNames: (0, helpers_1.getAttributeNames)(data, [
26
+ ...attributesToUpdate,
27
+ ...namesInCondition,
28
+ ]),
21
29
  ...args,
22
- }));
30
+ }))
31
+ .then((res) => args?.ReturnValues ? (0, util_dynamodb_1.unmarshall)(res.Attributes) : undefined);
23
32
  }
24
33
  exports.updateItem = updateItem;
25
34
  async function removeAttributes(key, attributes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moicky/dynamodb",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "description": "Contains a collection of convenience functions for working with AWS DynamoDB",
package/readme.md CHANGED
@@ -1,7 +1,5 @@
1
1
  # @moicky/dynamodb
2
2
 
3
- ## Stats
4
-
5
3
  ![](https://img.shields.io/github/languages/top/moicky/dynamodb)
6
4
  ![](https://img.shields.io/github/actions/workflow/status/moicky/dynamodb/npm-publish.yml?label=build)
7
5
  ![](https://img.shields.io/github/actions/workflow/status/moicky/dynamodb/run-tests.yml?label=tests)
@@ -14,6 +12,7 @@ Contains convenience functions for all major dynamodb operations. Requires very
14
12
 
15
13
  - 🎁 Will **automatically marshall and unmarshall** items
16
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`
17
16
  - 🔄 Will **retry** some operations (getItems, deleteItems) **up to 3 times** on unprocessed items
18
17
  - 🔒 When specifying an item using its keySchema, all additional attributes (apart from **PK** and **SK**) will be removed to avoid errors
19
18
  - 👻 Will **use placeholders** to avoid colliding with [reserved words](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html) if applicable
@@ -98,28 +97,20 @@ await getAllItems();
98
97
  ```ts
99
98
  import { deleteItem, deleteItems } from "@moicky/dynamodb";
100
99
 
101
- // Passing more than just the key is possible, but will be removed to avoid errors
102
-
103
100
  // Delete single item
104
101
  await deleteItem({
105
102
  PK: "User/1",
106
103
  SK: "Book/1",
107
- 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
108
105
  author: "F. Scott Fitzgerald",
109
106
  released: 1925,
110
107
  });
111
108
 
112
109
  // Delete multiple items
113
- // Keys will be grouped into batches of 25 and will be retried up to 3 times if there are unprocessed items
114
- // Will also only delete each keySchema once, even if it is present multiple times in the array to improve performance
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
115
112
  await deleteItems([
116
- {
117
- PK: "User/1",
118
- SK: "Book/1",
119
- title: "The Great Gatsby", // additional fields will be removed before sending
120
- author: "F. Scott Fitzgerald",
121
- released: 1925,
122
- },
113
+ { PK: "User/1", SK: "Book/1" },
123
114
  // ... infinite more items (will be grouped into batches of 25 due to aws limit) and retried up to 3 times
124
115
  ]);
125
116
  ```
@@ -129,27 +120,26 @@ await deleteItems([
129
120
  ```ts
130
121
  import { updateItem, removeAttributes } from "@moicky/dynamodb";
131
122
 
132
- // Passing more than just the key is possible, but will be removed to avoid errors
133
-
134
123
  // Update the item and overwrite all supplied fields
135
124
  await updateItem(
136
- {
137
- PK: "User/1",
138
- SK: "Book/1",
139
- title: "The Great Gatsby", // additional fields will be removed before sending
140
- },
125
+ { PK: "User/1", SK: "Book/1" },
141
126
  { description: "A book about a rich guy", author: "F. Scott Fitzgerald" }
142
127
  );
143
128
 
144
- // Completely remove fields from the item
145
- await removeAttributes(
146
- {
147
- PK: "User/1",
148
- SK: "Book/1",
149
- title: "The Great Gatsby", // additional fields will be removed before sending
150
- },
151
- ["description"]
129
+ await updateItem(
130
+ { PK: "User/1", SK: "Book/1" },
131
+ { released: 2000, maxReleased: 1950 }, // maxReleased will not be updated, since it is referenced inside the ConditionExpression
132
+ { ConditionExpression: "#released < :maxReleased" }
133
+ );
134
+
135
+ const newItem = await updateItem(
136
+ { PK: "User/1", SK: "Book/1" },
137
+ { released: 2000 },
138
+ { ReturnValues: "ALL_NEW" }
152
139
  );
140
+ console.log(newItem); // { "PK": "User/1", "SK": "Book/1", "released": 2000 }
141
+
142
+ await removeAttributes({ PK: "User/1", SK: "Book/1" }, ["description"]);
153
143
  ```
154
144
 
155
145
  ### Query Items
@@ -157,7 +147,7 @@ await removeAttributes(
157
147
  ```ts
158
148
  import { query, queryItems, queryAllItems } from "@moicky/dynamodb";
159
149
 
160
- // You have to use placeholders for the keyCondition & filterExpression:
150
+ // You HAVE TO use placeholders for the keyCondition & filterExpression:
161
151
  // prefix the attributeNames with a hash (#) and the attributeValues with a colon (:)
162
152
 
163
153
  // Query only using keyCondition and retrieve complete response
@@ -189,7 +179,7 @@ const booksWithFilter = await queryAllItems(
189
179
  to: 2000,
190
180
  },
191
181
  // additional args with filterExpression
192
- { FilterExpression: "#released BETWEEN :from AND :to" }
182
+ { FilterExpression: "#released BETWEEN :from AND :to" } // allows to override all args
193
183
  );
194
184
  ```
195
185
 
@@ -202,15 +192,14 @@ import { itemExists, getNewId } from "@moicky/dynamodb";
202
192
  const exists = await itemExists({ PK: "User/1", SK: "Book/1" });
203
193
 
204
194
  // Generate ascending ID
195
+
205
196
  // Example Structure 1: PK: "User/1", SK: "{{ ASCENDING_ID }}"
206
197
  // Last item: { PK: "User/1", SK: "00000009" }
207
-
208
198
  const id1 = await getNewId({ PK: "User/1" });
209
199
  console.log(id1); // "00000010"
210
200
 
211
201
  // Example Structure 2: PK: "User/1", SK: "Book/{{ ASCENDING_ID }}"
212
202
  // Last item: { PK: "User/1", SK: "Book/00000009" }
213
-
214
203
  const id2 = await getNewId({ PK: "User/1", SK: "Book" });
215
204
  console.log(id2); // "00000010"
216
205