triangle-utils 1.4.9 → 1.4.11
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/src/UtilsDynamoDB.d.ts +18 -14
- package/dist/src/UtilsDynamoDB.js +86 -43
- package/dist/src/f.d.ts +1 -0
- package/dist/src/f.js +17 -0
- package/package.json +1 -1
- package/src/UtilsDynamoDB.ts +110 -49
- package/src/f.ts +25 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare class UtilsDynamoDB {
|
|
2
2
|
private readonly dynamodb;
|
|
3
3
|
constructor(region: string);
|
|
4
|
+
get_table_key_names(table_name: string): Promise<string[] | undefined>;
|
|
4
5
|
scan(table: string, options?: {
|
|
5
6
|
filters?: Record<string, any>;
|
|
6
7
|
undefined_attribute_names?: string[];
|
|
@@ -10,27 +11,30 @@ export declare class UtilsDynamoDB {
|
|
|
10
11
|
}): Promise<Record<string, any>[]>;
|
|
11
12
|
get(table: string, key: Record<string, any>, consistent?: boolean): Promise<Record<string, any> | undefined>;
|
|
12
13
|
get_max(table: string, primary_key: Record<string, any>): Promise<Record<string, any> | undefined>;
|
|
13
|
-
query(
|
|
14
|
-
index_name?: string;
|
|
14
|
+
query(table_index_name: string, primary_key: Record<string, any>, options?: {
|
|
15
15
|
reverse?: boolean;
|
|
16
16
|
compile?: boolean;
|
|
17
|
+
project?: boolean;
|
|
18
|
+
attribute_names?: string[];
|
|
17
19
|
}): Promise<Record<string, any>[]>;
|
|
18
|
-
query_prefix(
|
|
19
|
-
index_name?: string;
|
|
20
|
+
query_prefix(table_index_name: string, primary_key: Record<string, any>, secondary_key_prefix: Record<string, string>, options?: {
|
|
20
21
|
reverse?: boolean;
|
|
21
22
|
compile?: boolean;
|
|
23
|
+
project?: boolean;
|
|
24
|
+
attribute_names?: string[];
|
|
22
25
|
}): Promise<Record<string, any>[]>;
|
|
23
|
-
query_range(
|
|
24
|
-
index_name?: string;
|
|
26
|
+
query_range(table_index_name: string, primary_key: Record<string, any>, secondary_key_range: Record<string, (string | number)[]>, options?: {
|
|
25
27
|
reverse?: boolean;
|
|
26
28
|
compile?: boolean;
|
|
29
|
+
project?: boolean;
|
|
30
|
+
attribute_names?: string[];
|
|
27
31
|
}): Promise<Record<string, any>[]>;
|
|
28
|
-
set(
|
|
29
|
-
append(
|
|
30
|
-
add(
|
|
31
|
-
remove(
|
|
32
|
-
create(
|
|
33
|
-
delete(
|
|
34
|
-
duplicate_attribute(
|
|
35
|
-
remove_attribute(
|
|
32
|
+
set(table_name: string, key: Record<string, any>, attributes: Record<string, any>): Promise<void>;
|
|
33
|
+
append(table_name: string, key: Record<string, any>, attributes: Record<string, any[]>): Promise<void>;
|
|
34
|
+
add(table_name: string, key: Record<string, any>, attributes: Record<string, any[]>): Promise<void>;
|
|
35
|
+
remove(table_name: string, key: Record<string, any>, attributes: string[]): Promise<void>;
|
|
36
|
+
create(table_name: string, key: Record<string, any>, attributes?: Record<string, any>): Promise<void>;
|
|
37
|
+
delete(table_name: string, key: Record<string, any>): Promise<void>;
|
|
38
|
+
duplicate_attribute(table_name: string, attribute_name: string, new_attribute_name: string): Promise<void>;
|
|
39
|
+
remove_attribute(table_name: string, attribute_name: string): Promise<undefined>;
|
|
36
40
|
}
|
|
@@ -87,6 +87,17 @@ export class UtilsDynamoDB {
|
|
|
87
87
|
constructor(region) {
|
|
88
88
|
this.dynamodb = new DynamoDB({ region: region });
|
|
89
89
|
}
|
|
90
|
+
async get_table_key_names(table_name) {
|
|
91
|
+
const table_metadata = await this.dynamodb.describeTable({
|
|
92
|
+
TableName: table_name
|
|
93
|
+
});
|
|
94
|
+
if (table_metadata.Table === undefined || table_metadata.Table.KeySchema === undefined) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
const table_key_names = table_metadata.Table.KeySchema.map(key => key.AttributeName)
|
|
98
|
+
.filter(table_key_name => table_key_name !== undefined);
|
|
99
|
+
return table_key_names;
|
|
100
|
+
}
|
|
90
101
|
async scan(table, options = {}) {
|
|
91
102
|
const filters = options.filters !== undefined ? options.filters : {};
|
|
92
103
|
const undefined_attribute_names = options.undefined_attribute_names !== undefined ? options.undefined_attribute_names : [];
|
|
@@ -173,11 +184,15 @@ export class UtilsDynamoDB {
|
|
|
173
184
|
}
|
|
174
185
|
return converted_output;
|
|
175
186
|
}
|
|
176
|
-
async query(
|
|
177
|
-
const
|
|
187
|
+
async query(table_index_name, primary_key, options = {}) {
|
|
188
|
+
const table_name = table_index_name.split(":")[0];
|
|
189
|
+
const index_name = table_index_name.split(":")[1];
|
|
178
190
|
const reverse = options.reverse !== undefined ? options.reverse : false;
|
|
179
191
|
const compile = options.compile !== undefined ? options.compile : true;
|
|
180
|
-
|
|
192
|
+
const project = options.project !== undefined ? options.project : true;
|
|
193
|
+
const attribute_names = options.attribute_names !== undefined ? options.attribute_names : [];
|
|
194
|
+
const table_key_names = await this.get_table_key_names(table_name);
|
|
195
|
+
if (table_key_names === undefined || Object.keys(primary_key).length !== 1) {
|
|
181
196
|
return [];
|
|
182
197
|
}
|
|
183
198
|
const key = Object.keys(primary_key)[0];
|
|
@@ -185,8 +200,9 @@ export class UtilsDynamoDB {
|
|
|
185
200
|
if (value === undefined) {
|
|
186
201
|
return [];
|
|
187
202
|
}
|
|
203
|
+
const projection_expression = attribute_names.map(attribute_name => "#" + attribute_name).join(", ");
|
|
188
204
|
const request = {
|
|
189
|
-
TableName:
|
|
205
|
+
TableName: table_name,
|
|
190
206
|
IndexName: index_name,
|
|
191
207
|
ExpressionAttributeNames: {
|
|
192
208
|
"#a": key
|
|
@@ -194,16 +210,27 @@ export class UtilsDynamoDB {
|
|
|
194
210
|
ExpressionAttributeValues: {
|
|
195
211
|
":a": value
|
|
196
212
|
},
|
|
213
|
+
ProjectionExpression: projection_expression.length > 0 ? projection_expression : undefined,
|
|
197
214
|
KeyConditionExpression: "#a = :a",
|
|
198
215
|
ScanIndexForward: !reverse
|
|
199
216
|
};
|
|
200
|
-
|
|
217
|
+
const items = await compile_pages(request, (request) => this.dynamodb.query(request), compile)
|
|
218
|
+
.then(async (items) => index_name === undefined || !project ? items :
|
|
219
|
+
await Promise.all(items.map(async (item) => {
|
|
220
|
+
return await this.get(table_name, Object.fromEntries(Object.entries(item).filter((([key_name, key_value]) => table_key_names.includes(key_name)))));
|
|
221
|
+
}))
|
|
222
|
+
.then(items => items.filter(item => item !== undefined)));
|
|
223
|
+
return items;
|
|
201
224
|
}
|
|
202
|
-
async query_prefix(
|
|
203
|
-
const
|
|
225
|
+
async query_prefix(table_index_name, primary_key, secondary_key_prefix, options = {}) {
|
|
226
|
+
const table_name = table_index_name.split(":")[0];
|
|
227
|
+
const index_name = table_index_name.split(":")[1];
|
|
204
228
|
const reverse = options.reverse !== undefined ? options.reverse : false;
|
|
205
229
|
const compile = options.compile !== undefined ? options.compile : true;
|
|
206
|
-
|
|
230
|
+
const project = options.project !== undefined ? options.project : true;
|
|
231
|
+
const attribute_names = options.attribute_names !== undefined ? options.attribute_names : [];
|
|
232
|
+
const table_key_names = await this.get_table_key_names(table_name);
|
|
233
|
+
if (table_key_names === undefined || Object.keys(primary_key).length !== 1 || Object.keys(secondary_key_prefix).length !== 1) {
|
|
207
234
|
return [];
|
|
208
235
|
}
|
|
209
236
|
const converted_primary_value = convert_input(Object.values(primary_key)[0]);
|
|
@@ -211,8 +238,9 @@ export class UtilsDynamoDB {
|
|
|
211
238
|
if (converted_primary_value === undefined || converted_secondary_prefix_value === undefined) {
|
|
212
239
|
return [];
|
|
213
240
|
}
|
|
241
|
+
const projection_expression = attribute_names.map(attribute_name => "#" + attribute_name).join(", ");
|
|
214
242
|
const request = {
|
|
215
|
-
TableName:
|
|
243
|
+
TableName: table_name,
|
|
216
244
|
IndexName: index_name,
|
|
217
245
|
ExpressionAttributeNames: {
|
|
218
246
|
"#a": Object.keys(primary_key)[0],
|
|
@@ -222,16 +250,27 @@ export class UtilsDynamoDB {
|
|
|
222
250
|
":a": converted_primary_value,
|
|
223
251
|
":b": converted_secondary_prefix_value
|
|
224
252
|
},
|
|
253
|
+
ProjectionExpression: projection_expression.length > 0 ? projection_expression : undefined,
|
|
225
254
|
KeyConditionExpression: "#a = :a AND begins_with(#b, :b)",
|
|
226
255
|
ScanIndexForward: !reverse
|
|
227
256
|
};
|
|
228
|
-
|
|
257
|
+
const items = await compile_pages(request, (request) => this.dynamodb.query(request), compile)
|
|
258
|
+
.then(async (items) => index_name === undefined || !project ? items :
|
|
259
|
+
await Promise.all(items.map(async (item) => {
|
|
260
|
+
return await this.get(table_name, Object.fromEntries(Object.entries(item).filter((([key_name, key_value]) => table_key_names.includes(key_name)))));
|
|
261
|
+
}))
|
|
262
|
+
.then(items => items.filter(item => item !== undefined)));
|
|
263
|
+
return items;
|
|
229
264
|
}
|
|
230
|
-
async query_range(
|
|
231
|
-
const
|
|
265
|
+
async query_range(table_index_name, primary_key, secondary_key_range, options = {}) {
|
|
266
|
+
const table_name = table_index_name.split(":")[0];
|
|
267
|
+
const index_name = table_index_name.split(":")[1];
|
|
232
268
|
const reverse = options.reverse !== undefined ? options.reverse : false;
|
|
233
269
|
const compile = options.compile !== undefined ? options.compile : true;
|
|
234
|
-
|
|
270
|
+
const project = options.project !== undefined ? options.project : true;
|
|
271
|
+
const attribute_names = options.attribute_names !== undefined ? options.attribute_names : [];
|
|
272
|
+
const table_key_names = await this.get_table_key_names(table_name);
|
|
273
|
+
if (table_key_names === undefined || Object.keys(primary_key).length !== 1 || Object.keys(secondary_key_range).length !== 1 || Object.values(secondary_key_range)[0].length !== 2) {
|
|
235
274
|
return [];
|
|
236
275
|
}
|
|
237
276
|
const converted_primary_value = convert_input(Object.values(primary_key)[0]);
|
|
@@ -240,8 +279,9 @@ export class UtilsDynamoDB {
|
|
|
240
279
|
if (converted_primary_value === undefined || converted_secondary_range_start_value === undefined || converted_secondary_range_end_value === undefined) {
|
|
241
280
|
return [];
|
|
242
281
|
}
|
|
282
|
+
const projection_expression = attribute_names.map(attribute_name => "#" + attribute_name).join(", ");
|
|
243
283
|
const request = {
|
|
244
|
-
TableName:
|
|
284
|
+
TableName: table_name,
|
|
245
285
|
IndexName: index_name,
|
|
246
286
|
ExpressionAttributeNames: {
|
|
247
287
|
"#a": Object.keys(primary_key)[0],
|
|
@@ -252,15 +292,22 @@ export class UtilsDynamoDB {
|
|
|
252
292
|
":b1": converted_secondary_range_start_value,
|
|
253
293
|
":b2": converted_secondary_range_end_value
|
|
254
294
|
},
|
|
295
|
+
ProjectionExpression: projection_expression.length > 0 ? projection_expression : undefined,
|
|
255
296
|
KeyConditionExpression: "#a = :a AND (#b BETWEEN :b1 AND :b2)",
|
|
256
297
|
ScanIndexForward: !reverse
|
|
257
298
|
};
|
|
258
|
-
|
|
299
|
+
const items = await compile_pages(request, (request) => this.dynamodb.query(request), compile)
|
|
300
|
+
.then(async (items) => index_name === undefined || !project ? items :
|
|
301
|
+
await Promise.all(items.map(async (item) => {
|
|
302
|
+
return await this.get(table_name, Object.fromEntries(Object.entries(item).filter((([key_name, key_value]) => table_key_names.includes(key_name)))));
|
|
303
|
+
}))
|
|
304
|
+
.then(items => items.filter(item => item !== undefined)));
|
|
305
|
+
return items;
|
|
259
306
|
}
|
|
260
|
-
async set(
|
|
307
|
+
async set(table_name, key, attributes) {
|
|
261
308
|
const converted_key = convert_input(key)?.M;
|
|
262
309
|
const request = {
|
|
263
|
-
TableName:
|
|
310
|
+
TableName: table_name,
|
|
264
311
|
Key: converted_key,
|
|
265
312
|
UpdateExpression: "set " + Object.keys(attributes)
|
|
266
313
|
.filter(attribute_name => !Object.keys(key).includes(attribute_name))
|
|
@@ -277,10 +324,10 @@ export class UtilsDynamoDB {
|
|
|
277
324
|
};
|
|
278
325
|
await this.dynamodb.updateItem(request);
|
|
279
326
|
}
|
|
280
|
-
async append(
|
|
327
|
+
async append(table_name, key, attributes) {
|
|
281
328
|
const converted_key = convert_input(key)?.M;
|
|
282
329
|
const request = {
|
|
283
|
-
TableName:
|
|
330
|
+
TableName: table_name,
|
|
284
331
|
Key: converted_key,
|
|
285
332
|
UpdateExpression: "set " + Object.keys(attributes)
|
|
286
333
|
.filter(attribute_name => attributes[attribute_name] !== undefined)
|
|
@@ -295,8 +342,8 @@ export class UtilsDynamoDB {
|
|
|
295
342
|
};
|
|
296
343
|
this.dynamodb.updateItem(request);
|
|
297
344
|
}
|
|
298
|
-
async add(
|
|
299
|
-
const item = await this.get(
|
|
345
|
+
async add(table_name, key, attributes) {
|
|
346
|
+
const item = await this.get(table_name, key, true);
|
|
300
347
|
if (item === undefined) {
|
|
301
348
|
return;
|
|
302
349
|
}
|
|
@@ -313,12 +360,12 @@ export class UtilsDynamoDB {
|
|
|
313
360
|
if (Object.values(new_attributes).flat().length === 0) {
|
|
314
361
|
return undefined;
|
|
315
362
|
}
|
|
316
|
-
return await this.append(
|
|
363
|
+
return await this.append(table_name, key, attributes);
|
|
317
364
|
}
|
|
318
|
-
async remove(
|
|
365
|
+
async remove(table_name, key, attributes) {
|
|
319
366
|
const converted_key = convert_input(key)?.M;
|
|
320
367
|
const request = {
|
|
321
|
-
TableName:
|
|
368
|
+
TableName: table_name,
|
|
322
369
|
Key: converted_key,
|
|
323
370
|
UpdateExpression: "remove " + attributes
|
|
324
371
|
.map(attribute_name => "#" + attribute_name).join(", "),
|
|
@@ -327,35 +374,35 @@ export class UtilsDynamoDB {
|
|
|
327
374
|
};
|
|
328
375
|
await this.dynamodb.updateItem(request);
|
|
329
376
|
}
|
|
330
|
-
async create(
|
|
331
|
-
const item = await this.get(
|
|
377
|
+
async create(table_name, key, attributes = {}) {
|
|
378
|
+
const item = await this.get(table_name, key, true);
|
|
332
379
|
if (item !== undefined) {
|
|
333
380
|
return;
|
|
334
381
|
}
|
|
335
382
|
const converted_key = convert_input(key)?.M;
|
|
336
383
|
const converted_attributes = convert_input(attributes)?.M;
|
|
337
384
|
await this.dynamodb.putItem({
|
|
338
|
-
TableName:
|
|
385
|
+
TableName: table_name,
|
|
339
386
|
Item: { ...converted_key, ...converted_attributes }
|
|
340
387
|
});
|
|
341
388
|
}
|
|
342
|
-
async delete(
|
|
389
|
+
async delete(table_name, key) {
|
|
343
390
|
const converted_key = convert_input(key)?.M;
|
|
344
391
|
await this.dynamodb.deleteItem({
|
|
345
|
-
TableName:
|
|
392
|
+
TableName: table_name,
|
|
346
393
|
Key: converted_key
|
|
347
394
|
});
|
|
348
395
|
}
|
|
349
|
-
async duplicate_attribute(
|
|
396
|
+
async duplicate_attribute(table_name, attribute_name, new_attribute_name) {
|
|
350
397
|
const table_metadata = await this.dynamodb.describeTable({
|
|
351
|
-
TableName:
|
|
398
|
+
TableName: table_name
|
|
352
399
|
});
|
|
353
400
|
if (table_metadata.Table === undefined || table_metadata.Table.KeySchema === undefined) {
|
|
354
401
|
return;
|
|
355
402
|
}
|
|
356
403
|
const table_key_names = table_metadata.Table.KeySchema.map(key => key.AttributeName)
|
|
357
404
|
.filter(table_key_name => table_key_name !== undefined);
|
|
358
|
-
const items = await this.scan(
|
|
405
|
+
const items = await this.scan(table_name, { attribute_names: table_key_names.concat([attribute_name, new_attribute_name]) });
|
|
359
406
|
if (items.filter(item => item[new_attribute_name] !== undefined).length > 0) {
|
|
360
407
|
console.log("Cannot rename.", new_attribute_name, "is an existing item.");
|
|
361
408
|
return;
|
|
@@ -365,23 +412,19 @@ export class UtilsDynamoDB {
|
|
|
365
412
|
continue;
|
|
366
413
|
}
|
|
367
414
|
const key = Object.fromEntries(table_key_names.map(key_name => [key_name, item[key_name]]));
|
|
368
|
-
await this.set(
|
|
415
|
+
await this.set(table_name, key, { [new_attribute_name]: item[attribute_name] });
|
|
369
416
|
}
|
|
370
417
|
}
|
|
371
|
-
async remove_attribute(
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if (table_metadata.Table === undefined || table_metadata.Table.KeySchema === undefined) {
|
|
376
|
-
return;
|
|
418
|
+
async remove_attribute(table_name, attribute_name) {
|
|
419
|
+
const table_key_names = await this.get_table_key_names(table_name);
|
|
420
|
+
if (table_key_names === undefined) {
|
|
421
|
+
return undefined;
|
|
377
422
|
}
|
|
378
|
-
const
|
|
379
|
-
.filter(table_key_name => table_key_name !== undefined);
|
|
380
|
-
const items = await this.scan(table)
|
|
423
|
+
const items = await this.scan(table_name)
|
|
381
424
|
.then(items => items.filter(item => item[attribute_name] !== undefined));
|
|
382
425
|
for (const item of items) {
|
|
383
426
|
const key = Object.fromEntries(table_key_names.map(key_name => [key_name, item[key_name]]));
|
|
384
|
-
await this.remove(
|
|
427
|
+
await this.remove(table_name, key, [attribute_name]);
|
|
385
428
|
}
|
|
386
429
|
}
|
|
387
430
|
}
|
package/dist/src/f.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/src/f.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SecretsManager } from "@aws-sdk/client-secrets-manager";
|
|
2
|
+
import { TriangleUtils } from "./index.js";
|
|
3
|
+
const secret_name = "triage_config";
|
|
4
|
+
const secrets_manager = new SecretsManager({ region: "us-east-1" });
|
|
5
|
+
const response = await secrets_manager.getSecretValue({
|
|
6
|
+
SecretId: secret_name
|
|
7
|
+
});
|
|
8
|
+
const api_keys = JSON.parse(response?.SecretString || "");
|
|
9
|
+
const config = {
|
|
10
|
+
google_email: "louishou@triangleanalytics.com",
|
|
11
|
+
alerts_email: "alerts@triangleanalytics.com",
|
|
12
|
+
region: "us-east-1",
|
|
13
|
+
...api_keys
|
|
14
|
+
};
|
|
15
|
+
const utils = new TriangleUtils(config);
|
|
16
|
+
const foods = await utils.dynamodb.query("triage_docket_documents:register_document_id", { register_document_id: "E6-17065" });
|
|
17
|
+
console.log(foods);
|
package/package.json
CHANGED
package/src/UtilsDynamoDB.ts
CHANGED
|
@@ -91,6 +91,20 @@ export class UtilsDynamoDB {
|
|
|
91
91
|
this.dynamodb = new DynamoDB({ region : region })
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
async get_table_key_names(
|
|
95
|
+
table_name : string
|
|
96
|
+
) : Promise<string[] | undefined> {
|
|
97
|
+
const table_metadata = await this.dynamodb.describeTable({
|
|
98
|
+
TableName : table_name
|
|
99
|
+
})
|
|
100
|
+
if (table_metadata.Table === undefined || table_metadata.Table.KeySchema === undefined) {
|
|
101
|
+
return undefined
|
|
102
|
+
}
|
|
103
|
+
const table_key_names = table_metadata.Table.KeySchema.map(key => key.AttributeName)
|
|
104
|
+
.filter(table_key_name => table_key_name !== undefined)
|
|
105
|
+
return table_key_names
|
|
106
|
+
}
|
|
107
|
+
|
|
94
108
|
async scan(
|
|
95
109
|
table : string,
|
|
96
110
|
options : {
|
|
@@ -201,18 +215,24 @@ export class UtilsDynamoDB {
|
|
|
201
215
|
}
|
|
202
216
|
|
|
203
217
|
async query(
|
|
204
|
-
|
|
218
|
+
table_index_name : string,
|
|
205
219
|
primary_key : Record<string, any>,
|
|
206
220
|
options : {
|
|
207
|
-
index_name? : string,
|
|
208
221
|
reverse? : boolean,
|
|
209
|
-
compile? : boolean
|
|
222
|
+
compile? : boolean,
|
|
223
|
+
project? : boolean,
|
|
224
|
+
attribute_names? : string[]
|
|
210
225
|
} = {}
|
|
211
226
|
) : Promise<Record<string, any>[]>{
|
|
212
|
-
const
|
|
227
|
+
const table_name : string = table_index_name.split(":")[0]
|
|
228
|
+
const index_name : string | undefined = table_index_name.split(":")[1]
|
|
213
229
|
const reverse = options.reverse !== undefined ? options.reverse : false
|
|
214
230
|
const compile = options.compile !== undefined ? options.compile : true
|
|
215
|
-
|
|
231
|
+
const project = options.project !== undefined ? options.project : true
|
|
232
|
+
const attribute_names : string[] = options.attribute_names !== undefined ? options.attribute_names : []
|
|
233
|
+
|
|
234
|
+
const table_key_names = await this.get_table_key_names(table_name)
|
|
235
|
+
if (table_key_names === undefined || Object.keys(primary_key).length !== 1) {
|
|
216
236
|
return []
|
|
217
237
|
}
|
|
218
238
|
const key = Object.keys(primary_key)[0]
|
|
@@ -220,8 +240,9 @@ export class UtilsDynamoDB {
|
|
|
220
240
|
if (value === undefined) {
|
|
221
241
|
return []
|
|
222
242
|
}
|
|
243
|
+
const projection_expression = attribute_names.map(attribute_name => "#" + attribute_name).join(", ")
|
|
223
244
|
const request : QueryCommandInput = {
|
|
224
|
-
TableName :
|
|
245
|
+
TableName : table_name,
|
|
225
246
|
IndexName : index_name,
|
|
226
247
|
ExpressionAttributeNames: {
|
|
227
248
|
"#a": key
|
|
@@ -229,26 +250,42 @@ export class UtilsDynamoDB {
|
|
|
229
250
|
ExpressionAttributeValues: {
|
|
230
251
|
":a": value
|
|
231
252
|
},
|
|
253
|
+
ProjectionExpression : projection_expression.length > 0 ? projection_expression : undefined,
|
|
232
254
|
KeyConditionExpression: "#a = :a",
|
|
233
255
|
ScanIndexForward : !reverse
|
|
234
256
|
}
|
|
235
|
-
|
|
257
|
+
const items = await compile_pages(request, (request) => this.dynamodb.query(request), compile)
|
|
258
|
+
.then(async items => index_name === undefined || !project ? items :
|
|
259
|
+
await Promise.all(items.map(async item => {
|
|
260
|
+
return await this.get(table_name,
|
|
261
|
+
Object.fromEntries(Object.entries(item).filter((([key_name, key_value]) => table_key_names.includes(key_name))))
|
|
262
|
+
)
|
|
263
|
+
}))
|
|
264
|
+
.then(items => items.filter(item => item !== undefined))
|
|
265
|
+
)
|
|
266
|
+
return items
|
|
236
267
|
}
|
|
237
268
|
|
|
238
269
|
async query_prefix(
|
|
239
|
-
|
|
270
|
+
table_index_name : string,
|
|
240
271
|
primary_key : Record<string, any>,
|
|
241
272
|
secondary_key_prefix : Record<string, string>,
|
|
242
273
|
options : {
|
|
243
|
-
index_name? : string,
|
|
244
274
|
reverse? : boolean,
|
|
245
|
-
compile? : boolean
|
|
275
|
+
compile? : boolean,
|
|
276
|
+
project? : boolean,
|
|
277
|
+
attribute_names? : string[]
|
|
246
278
|
} = {}
|
|
247
279
|
) : Promise<Record<string, any>[]>{
|
|
248
|
-
const
|
|
280
|
+
const table_name : string = table_index_name.split(":")[0]
|
|
281
|
+
const index_name : string | undefined = table_index_name.split(":")[1]
|
|
249
282
|
const reverse = options.reverse !== undefined ? options.reverse : false
|
|
250
283
|
const compile = options.compile !== undefined ? options.compile : true
|
|
251
|
-
|
|
284
|
+
const project = options.project !== undefined ? options.project : true
|
|
285
|
+
const attribute_names : string[] = options.attribute_names !== undefined ? options.attribute_names : []
|
|
286
|
+
|
|
287
|
+
const table_key_names = await this.get_table_key_names(table_name)
|
|
288
|
+
if (table_key_names === undefined || Object.keys(primary_key).length !== 1 || Object.keys(secondary_key_prefix).length !== 1) {
|
|
252
289
|
return []
|
|
253
290
|
}
|
|
254
291
|
const converted_primary_value = convert_input(Object.values(primary_key)[0])
|
|
@@ -256,8 +293,9 @@ export class UtilsDynamoDB {
|
|
|
256
293
|
if (converted_primary_value === undefined || converted_secondary_prefix_value === undefined) {
|
|
257
294
|
return []
|
|
258
295
|
}
|
|
296
|
+
const projection_expression = attribute_names.map(attribute_name => "#" + attribute_name).join(", ")
|
|
259
297
|
const request : QueryCommandInput = {
|
|
260
|
-
TableName :
|
|
298
|
+
TableName : table_name,
|
|
261
299
|
IndexName : index_name,
|
|
262
300
|
ExpressionAttributeNames: {
|
|
263
301
|
"#a": Object.keys(primary_key)[0],
|
|
@@ -267,26 +305,42 @@ export class UtilsDynamoDB {
|
|
|
267
305
|
":a": converted_primary_value,
|
|
268
306
|
":b": converted_secondary_prefix_value
|
|
269
307
|
},
|
|
308
|
+
ProjectionExpression : projection_expression.length > 0 ? projection_expression : undefined,
|
|
270
309
|
KeyConditionExpression: "#a = :a AND begins_with(#b, :b)",
|
|
271
310
|
ScanIndexForward : !reverse
|
|
272
311
|
}
|
|
273
|
-
|
|
312
|
+
const items = await compile_pages(request, (request) => this.dynamodb.query(request), compile)
|
|
313
|
+
.then(async items => index_name === undefined || !project ? items :
|
|
314
|
+
await Promise.all(items.map(async item => {
|
|
315
|
+
return await this.get(table_name,
|
|
316
|
+
Object.fromEntries(Object.entries(item).filter((([key_name, key_value]) => table_key_names.includes(key_name))))
|
|
317
|
+
)
|
|
318
|
+
}))
|
|
319
|
+
.then(items => items.filter(item => item !== undefined))
|
|
320
|
+
)
|
|
321
|
+
return items
|
|
274
322
|
}
|
|
275
323
|
|
|
276
324
|
async query_range(
|
|
277
|
-
|
|
325
|
+
table_index_name : string,
|
|
278
326
|
primary_key : Record<string, any>,
|
|
279
327
|
secondary_key_range : Record<string, (string|number)[]>,
|
|
280
328
|
options : {
|
|
281
|
-
index_name? : string,
|
|
282
329
|
reverse? : boolean,
|
|
283
|
-
compile? : boolean
|
|
330
|
+
compile? : boolean,
|
|
331
|
+
project? : boolean,
|
|
332
|
+
attribute_names? : string[]
|
|
284
333
|
} = {}
|
|
285
334
|
) : Promise<Record<string, any>[]>{
|
|
286
|
-
const
|
|
335
|
+
const table_name : string = table_index_name.split(":")[0]
|
|
336
|
+
const index_name : string | undefined = table_index_name.split(":")[1]
|
|
287
337
|
const reverse = options.reverse !== undefined ? options.reverse : false
|
|
288
338
|
const compile = options.compile !== undefined ? options.compile : true
|
|
289
|
-
|
|
339
|
+
const project = options.project !== undefined ? options.project : true
|
|
340
|
+
const attribute_names : string[] = options.attribute_names !== undefined ? options.attribute_names : []
|
|
341
|
+
|
|
342
|
+
const table_key_names = await this.get_table_key_names(table_name)
|
|
343
|
+
if (table_key_names === undefined || Object.keys(primary_key).length !== 1 || Object.keys(secondary_key_range).length !== 1 || Object.values(secondary_key_range)[0].length !== 2) {
|
|
290
344
|
return []
|
|
291
345
|
}
|
|
292
346
|
const converted_primary_value = convert_input(Object.values(primary_key)[0])
|
|
@@ -295,8 +349,9 @@ export class UtilsDynamoDB {
|
|
|
295
349
|
if (converted_primary_value === undefined || converted_secondary_range_start_value === undefined || converted_secondary_range_end_value === undefined) {
|
|
296
350
|
return []
|
|
297
351
|
}
|
|
352
|
+
const projection_expression = attribute_names.map(attribute_name => "#" + attribute_name).join(", ")
|
|
298
353
|
const request : QueryCommandInput = {
|
|
299
|
-
TableName :
|
|
354
|
+
TableName : table_name,
|
|
300
355
|
IndexName : index_name,
|
|
301
356
|
ExpressionAttributeNames: {
|
|
302
357
|
"#a": Object.keys(primary_key)[0],
|
|
@@ -307,17 +362,27 @@ export class UtilsDynamoDB {
|
|
|
307
362
|
":b1": converted_secondary_range_start_value,
|
|
308
363
|
":b2": converted_secondary_range_end_value
|
|
309
364
|
},
|
|
365
|
+
ProjectionExpression : projection_expression.length > 0 ? projection_expression : undefined,
|
|
310
366
|
KeyConditionExpression: "#a = :a AND (#b BETWEEN :b1 AND :b2)",
|
|
311
367
|
ScanIndexForward : !reverse
|
|
312
368
|
}
|
|
313
|
-
|
|
369
|
+
const items = await compile_pages(request, (request) => this.dynamodb.query(request), compile)
|
|
370
|
+
.then(async items => index_name === undefined || !project ? items :
|
|
371
|
+
await Promise.all(items.map(async item => {
|
|
372
|
+
return await this.get(table_name,
|
|
373
|
+
Object.fromEntries(Object.entries(item).filter((([key_name, key_value]) => table_key_names.includes(key_name))))
|
|
374
|
+
)
|
|
375
|
+
}))
|
|
376
|
+
.then(items => items.filter(item => item !== undefined))
|
|
377
|
+
)
|
|
378
|
+
return items
|
|
314
379
|
}
|
|
315
380
|
|
|
316
|
-
async set(
|
|
381
|
+
async set(table_name : string, key : Record<string, any>, attributes : Record<string, any>) : Promise<void> {
|
|
317
382
|
const converted_key = convert_input(key)?.M
|
|
318
383
|
|
|
319
384
|
const request : UpdateItemCommandInput = {
|
|
320
|
-
TableName :
|
|
385
|
+
TableName : table_name,
|
|
321
386
|
Key : converted_key,
|
|
322
387
|
UpdateExpression: "set " + Object.keys(attributes)
|
|
323
388
|
.filter(attribute_name => !Object.keys(key).includes(attribute_name))
|
|
@@ -338,11 +403,11 @@ export class UtilsDynamoDB {
|
|
|
338
403
|
await this.dynamodb.updateItem(request)
|
|
339
404
|
}
|
|
340
405
|
|
|
341
|
-
async append(
|
|
406
|
+
async append(table_name : string, key : Record<string, any>, attributes : Record<string, any[]>) : Promise<void>{
|
|
342
407
|
const converted_key = convert_input(key)?.M
|
|
343
408
|
|
|
344
409
|
const request : UpdateItemCommandInput = {
|
|
345
|
-
TableName :
|
|
410
|
+
TableName : table_name,
|
|
346
411
|
Key : converted_key,
|
|
347
412
|
UpdateExpression: "set " + Object.keys(attributes)
|
|
348
413
|
.filter(attribute_name => attributes[attribute_name] !== undefined)
|
|
@@ -360,8 +425,8 @@ export class UtilsDynamoDB {
|
|
|
360
425
|
this.dynamodb.updateItem(request)
|
|
361
426
|
}
|
|
362
427
|
|
|
363
|
-
async add(
|
|
364
|
-
const item = await this.get(
|
|
428
|
+
async add(table_name : string, key : Record<string, any>, attributes : Record<string, any[]>) : Promise<void> {
|
|
429
|
+
const item = await this.get(table_name, key, true)
|
|
365
430
|
if (item === undefined) {
|
|
366
431
|
return
|
|
367
432
|
}
|
|
@@ -378,14 +443,14 @@ export class UtilsDynamoDB {
|
|
|
378
443
|
if (Object.values(new_attributes).flat().length === 0) {
|
|
379
444
|
return undefined
|
|
380
445
|
}
|
|
381
|
-
return await this.append(
|
|
446
|
+
return await this.append(table_name, key, attributes)
|
|
382
447
|
}
|
|
383
448
|
|
|
384
|
-
async remove(
|
|
449
|
+
async remove(table_name : string, key : Record<string, any>, attributes : string[]) : Promise<void> {
|
|
385
450
|
const converted_key = convert_input(key)?.M
|
|
386
451
|
|
|
387
452
|
const request : UpdateItemCommandInput = {
|
|
388
|
-
TableName :
|
|
453
|
+
TableName : table_name,
|
|
389
454
|
Key : converted_key,
|
|
390
455
|
UpdateExpression: "remove " + attributes
|
|
391
456
|
.map(attribute_name => "#" + attribute_name).join(", "),
|
|
@@ -396,37 +461,37 @@ export class UtilsDynamoDB {
|
|
|
396
461
|
await this.dynamodb.updateItem(request)
|
|
397
462
|
}
|
|
398
463
|
|
|
399
|
-
async create(
|
|
400
|
-
const item = await this.get(
|
|
464
|
+
async create(table_name : string, key : Record<string, any>, attributes : Record<string, any> = {}) : Promise<void> {
|
|
465
|
+
const item = await this.get(table_name, key, true)
|
|
401
466
|
if (item !== undefined) {
|
|
402
467
|
return
|
|
403
468
|
}
|
|
404
469
|
const converted_key = convert_input(key)?.M
|
|
405
470
|
const converted_attributes = convert_input(attributes)?.M
|
|
406
471
|
await this.dynamodb.putItem({
|
|
407
|
-
TableName :
|
|
472
|
+
TableName : table_name,
|
|
408
473
|
Item : { ...converted_key, ...converted_attributes }
|
|
409
474
|
})
|
|
410
475
|
}
|
|
411
476
|
|
|
412
|
-
async delete(
|
|
477
|
+
async delete(table_name : string, key : Record<string, any>) : Promise<void> {
|
|
413
478
|
const converted_key = convert_input(key)?.M
|
|
414
479
|
await this.dynamodb.deleteItem({
|
|
415
|
-
TableName:
|
|
480
|
+
TableName: table_name,
|
|
416
481
|
Key: converted_key
|
|
417
482
|
})
|
|
418
483
|
}
|
|
419
484
|
|
|
420
|
-
async duplicate_attribute(
|
|
485
|
+
async duplicate_attribute(table_name : string, attribute_name : string, new_attribute_name : string) : Promise<void>{
|
|
421
486
|
const table_metadata = await this.dynamodb.describeTable({
|
|
422
|
-
TableName :
|
|
487
|
+
TableName : table_name
|
|
423
488
|
})
|
|
424
489
|
if (table_metadata.Table === undefined || table_metadata.Table.KeySchema === undefined) {
|
|
425
490
|
return
|
|
426
491
|
}
|
|
427
492
|
const table_key_names = table_metadata.Table.KeySchema.map(key => key.AttributeName)
|
|
428
493
|
.filter(table_key_name => table_key_name !== undefined)
|
|
429
|
-
const items = await this.scan(
|
|
494
|
+
const items = await this.scan(table_name, { attribute_names : table_key_names.concat([attribute_name, new_attribute_name]) })
|
|
430
495
|
if (items.filter(item => item[new_attribute_name] !== undefined).length > 0) {
|
|
431
496
|
console.log("Cannot rename.", new_attribute_name, "is an existing item.")
|
|
432
497
|
return
|
|
@@ -436,24 +501,20 @@ export class UtilsDynamoDB {
|
|
|
436
501
|
continue
|
|
437
502
|
}
|
|
438
503
|
const key = Object.fromEntries(table_key_names.map(key_name => [key_name, item[key_name]]))
|
|
439
|
-
await this.set(
|
|
504
|
+
await this.set(table_name, key, { [new_attribute_name] : item[attribute_name] })
|
|
440
505
|
}
|
|
441
506
|
}
|
|
442
507
|
|
|
443
|
-
async remove_attribute(
|
|
444
|
-
const
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (table_metadata.Table === undefined || table_metadata.Table.KeySchema === undefined) {
|
|
448
|
-
return
|
|
508
|
+
async remove_attribute(table_name : string, attribute_name : string) {
|
|
509
|
+
const table_key_names = await this.get_table_key_names(table_name)
|
|
510
|
+
if (table_key_names === undefined) {
|
|
511
|
+
return undefined
|
|
449
512
|
}
|
|
450
|
-
const
|
|
451
|
-
.filter(table_key_name => table_key_name !== undefined)
|
|
452
|
-
const items = await this.scan(table)
|
|
513
|
+
const items = await this.scan(table_name)
|
|
453
514
|
.then(items => items.filter(item => item[attribute_name] !== undefined))
|
|
454
515
|
for (const item of items) {
|
|
455
516
|
const key = Object.fromEntries(table_key_names.map(key_name => [key_name, item[key_name]]))
|
|
456
|
-
await this.remove(
|
|
517
|
+
await this.remove(table_name, key, [attribute_name])
|
|
457
518
|
}
|
|
458
519
|
}
|
|
459
520
|
}
|
package/src/f.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { SecretsManager } from "@aws-sdk/client-secrets-manager"
|
|
2
|
+
import { TriangleUtils } from "."
|
|
3
|
+
|
|
4
|
+
const secret_name = "triage_config"
|
|
5
|
+
|
|
6
|
+
const secrets_manager = new SecretsManager({ region: "us-east-1" })
|
|
7
|
+
|
|
8
|
+
const response = await secrets_manager.getSecretValue({
|
|
9
|
+
SecretId: secret_name
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const api_keys = JSON.parse(response?.SecretString || "")
|
|
13
|
+
|
|
14
|
+
const config = {
|
|
15
|
+
google_email : "louishou@triangleanalytics.com",
|
|
16
|
+
alerts_email : "alerts@triangleanalytics.com",
|
|
17
|
+
region : "us-east-1",
|
|
18
|
+
...api_keys
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const utils = new TriangleUtils(config)
|
|
22
|
+
|
|
23
|
+
const foods = await utils.dynamodb.query("triage_docket_documents:register_document_id", { register_document_id : "E6-17065" })
|
|
24
|
+
|
|
25
|
+
console.log(foods)
|