ag-common 0.0.723 → 0.0.725
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/api/helpers/dynamo.d.ts +54 -51
- package/dist/api/helpers/dynamo.js +193 -241
- package/package.json +1 -1
|
@@ -1,77 +1,80 @@
|
|
|
1
1
|
import { DynamoDBDocument } from '@aws-sdk/lib-dynamodb';
|
|
2
2
|
import type { AwsCredentialIdentity } from '@smithy/types';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
type DynamoDBError = {
|
|
4
|
+
error: string;
|
|
5
|
+
};
|
|
6
|
+
type DynamoDBSuccess<T> = {
|
|
7
|
+
data: T;
|
|
8
|
+
};
|
|
9
|
+
type DynamoDBResult<T> = DynamoDBSuccess<T> | DynamoDBError;
|
|
10
|
+
interface Key {
|
|
11
|
+
[key: string]: string | number;
|
|
12
|
+
}
|
|
13
|
+
interface DynamoFilter {
|
|
14
|
+
filterExpression: string;
|
|
15
|
+
attrNames: Record<string, string>;
|
|
16
|
+
attrValues?: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
interface ScanOptions {
|
|
19
|
+
filter?: DynamoFilter;
|
|
20
|
+
requiredAttributeList?: string[];
|
|
21
|
+
limit?: number;
|
|
22
|
+
}
|
|
23
|
+
interface DynamoQueryParams {
|
|
24
|
+
tableName: string;
|
|
25
|
+
pkName: string;
|
|
26
|
+
pkValue: string | number;
|
|
27
|
+
pkOperator?: '=' | '<' | '>' | '<=' | '>=';
|
|
28
|
+
skName?: string;
|
|
29
|
+
skValue?: string | number | [string | number, string | number];
|
|
30
|
+
skOperator?: '=' | '<' | '>' | '<=' | '>=' | 'BETWEEN' | 'BEGINS_WITH';
|
|
31
|
+
indexName?: string;
|
|
32
|
+
limit?: number;
|
|
33
|
+
startKey?: Key;
|
|
34
|
+
filterName?: string;
|
|
35
|
+
filterValue?: unknown;
|
|
36
|
+
filterOperator?: string;
|
|
37
|
+
sortAscending?: boolean;
|
|
38
|
+
}
|
|
5
39
|
export declare let dynamoDb: DynamoDBDocument;
|
|
6
|
-
export declare const
|
|
7
|
-
|
|
40
|
+
export declare const setDynamo: (region: string, credentials?: AwsCredentialIdentity) => DynamoDBDocument;
|
|
41
|
+
export declare const putDynamo: <T extends Record<string, unknown>>(item: T, tableName: string, opt?: {
|
|
8
42
|
pkName?: string;
|
|
9
|
-
}) => Promise<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export declare const batchWrite: <T extends Record<string, any>>(tableName: string, itemsIn: T[]) => Promise<{
|
|
13
|
-
error?: string;
|
|
14
|
-
}>;
|
|
15
|
-
export declare const batchDelete: ({ tableName, keys, pkName, }: {
|
|
43
|
+
}) => Promise<DynamoDBResult<void>>;
|
|
44
|
+
export declare const batchWrite: <T extends Record<string, unknown>>(tableName: string, items: T[]) => Promise<DynamoDBResult<void>>;
|
|
45
|
+
export declare const batchDelete: (params: {
|
|
16
46
|
tableName: string;
|
|
17
47
|
keys: string[];
|
|
18
48
|
pkName: string;
|
|
19
|
-
}) => Promise<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
filter?: {
|
|
24
|
-
filterExpression: string;
|
|
25
|
-
attrNames: Record<string, string>;
|
|
26
|
-
attrValues?: Record<string, string>;
|
|
27
|
-
};
|
|
28
|
-
/** ProjectionExpression. will csv values */
|
|
29
|
-
requiredAttributeList?: string[];
|
|
30
|
-
/** default =ALL */
|
|
31
|
-
limit?: number;
|
|
32
|
-
}) => Promise<{
|
|
33
|
-
data: T[];
|
|
34
|
-
} | {
|
|
35
|
-
error: string;
|
|
36
|
-
}>;
|
|
37
|
-
export declare const getItemsDynamo: <T>({ tableName, items, }: {
|
|
49
|
+
}) => Promise<DynamoDBResult<void>>;
|
|
50
|
+
export declare const scan: <T>(tableName: string, options?: ScanOptions) => Promise<DynamoDBResult<T[]>>;
|
|
51
|
+
export declare const getItemsDynamo: <T>(params: {
|
|
52
|
+
tableName: string;
|
|
38
53
|
items: {
|
|
39
54
|
pkName: string;
|
|
40
55
|
pkValue: string;
|
|
41
56
|
}[];
|
|
57
|
+
}) => Promise<DynamoDBResult<T[]>>;
|
|
58
|
+
export declare const getItemDynamo: <T>(params: {
|
|
42
59
|
tableName: string;
|
|
43
|
-
}) => Promise<{
|
|
44
|
-
data: T[];
|
|
45
|
-
} | {
|
|
46
|
-
error: string;
|
|
47
|
-
}>;
|
|
48
|
-
export declare const getItemDynamo: <T>({ tableName, pkName, pkValue, }: {
|
|
49
60
|
pkName: string;
|
|
50
61
|
pkValue: string;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
data: T;
|
|
54
|
-
} | {
|
|
55
|
-
error: string;
|
|
56
|
-
}>;
|
|
57
|
-
export declare const queryDynamo: <T>({ tableName, pkName, pkValue, pkOperator, skName, skValue, skOperator, indexName, limit, startKey, filterName, filterValue, filterOperator, sortAscending, }: IQueryDynamo) => Promise<{
|
|
62
|
+
}) => Promise<DynamoDBResult<T>>;
|
|
63
|
+
export declare const queryDynamo: <T>(params: DynamoQueryParams) => Promise<{
|
|
58
64
|
data: T[];
|
|
59
65
|
startKey?: Key;
|
|
60
66
|
} | {
|
|
61
67
|
error: string;
|
|
62
68
|
}>;
|
|
63
69
|
export declare const getDynamoTtlDays: (days: number) => number;
|
|
64
|
-
export declare const getDynamoTtlMinutes: (
|
|
65
|
-
export declare const wipeTable: (tableName: string) => Promise<
|
|
66
|
-
|
|
67
|
-
}>;
|
|
68
|
-
/** gets all fields in dynamokeys, and moves them into update expressions. eg will turn item.yourFieldName, into a dynamo write into field "yourFieldName" */
|
|
69
|
-
export declare const getDynamoUpdates: (item: Record<string, string | number | boolean>, opt?: {
|
|
70
|
-
/** default PK. will also exclude null or undefined */
|
|
70
|
+
export declare const getDynamoTtlMinutes: (minutes: number) => number;
|
|
71
|
+
export declare const wipeTable: (tableName: string) => Promise<DynamoDBResult<void>>;
|
|
72
|
+
export declare const getDynamoUpdates: <T extends Record<string, unknown>>(item: T, options?: {
|
|
71
73
|
excludeKeys?: string[];
|
|
72
74
|
}) => {
|
|
73
75
|
UpdateExpression: string;
|
|
74
76
|
ExpressionAttributeNames: Record<string, string>;
|
|
75
|
-
ExpressionAttributeValues: Record<string,
|
|
77
|
+
ExpressionAttributeValues: Record<string, unknown>;
|
|
76
78
|
ReturnValues: 'UPDATED_NEW';
|
|
77
79
|
};
|
|
80
|
+
export {};
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/* eslint-disable guard-for-in */
|
|
3
|
-
/* eslint-disable no-restricted-syntax */
|
|
4
|
-
/* eslint-disable no-await-in-loop */
|
|
5
|
-
/* eslint-disable prefer-const */
|
|
6
2
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
7
3
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
8
4
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -13,336 +9,292 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
13
9
|
});
|
|
14
10
|
};
|
|
15
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.getDynamoUpdates = exports.wipeTable = exports.getDynamoTtlMinutes = exports.getDynamoTtlDays = exports.queryDynamo = exports.getItemDynamo = exports.getItemsDynamo = exports.scan = exports.batchDelete = exports.batchWrite = exports.putDynamo = exports.
|
|
12
|
+
exports.getDynamoUpdates = exports.wipeTable = exports.getDynamoTtlMinutes = exports.getDynamoTtlDays = exports.queryDynamo = exports.getItemDynamo = exports.getItemsDynamo = exports.scan = exports.batchDelete = exports.batchWrite = exports.putDynamo = exports.setDynamo = exports.dynamoDb = void 0;
|
|
17
13
|
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
18
14
|
const lib_dynamodb_1 = require("@aws-sdk/lib-dynamodb");
|
|
19
|
-
// ES6 import
|
|
20
15
|
const array_1 = require("../../common/helpers/array");
|
|
21
16
|
const async_1 = require("../../common/helpers/async");
|
|
22
17
|
const log_1 = require("../../common/helpers/log");
|
|
23
18
|
const sleep_1 = require("../../common/helpers/sleep");
|
|
24
|
-
const
|
|
19
|
+
const RETRY_CONFIG = {
|
|
20
|
+
maxRetries: 3,
|
|
21
|
+
baseDelay: 2000,
|
|
22
|
+
};
|
|
23
|
+
const isError = (result) => 'error' in result;
|
|
24
|
+
const withRetry = (operation, operationName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
let retryCount = 0;
|
|
26
|
+
// eslint-disable-next-line
|
|
27
|
+
while (true) {
|
|
28
|
+
try {
|
|
29
|
+
return yield operation();
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
const error = e;
|
|
33
|
+
const errorString = error.toString();
|
|
34
|
+
if (errorString.includes('429') ||
|
|
35
|
+
errorString.includes('ProvisionedThroughputExceeded')) {
|
|
36
|
+
retryCount++;
|
|
37
|
+
if (retryCount >= RETRY_CONFIG.maxRetries) {
|
|
38
|
+
(0, log_1.warn)(`${operationName}: Max retries exceeded`);
|
|
39
|
+
throw error;
|
|
40
|
+
}
|
|
41
|
+
const delay = RETRY_CONFIG.baseDelay * Math.pow(2, retryCount - 1);
|
|
42
|
+
(0, log_1.warn)(`${operationName}: Throttled. Retry ${retryCount}`);
|
|
43
|
+
yield (0, sleep_1.sleep)(delay);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
25
50
|
const setDynamo = (region, credentials) => {
|
|
26
|
-
|
|
27
|
-
|
|
51
|
+
const client = new client_dynamodb_1.DynamoDBClient({ region, credentials });
|
|
52
|
+
exports.dynamoDb = lib_dynamodb_1.DynamoDBDocument.from(client, {
|
|
28
53
|
marshallOptions: { removeUndefinedValues: true },
|
|
29
54
|
});
|
|
30
|
-
exports.dynamoDb
|
|
31
|
-
return ddbDocClient;
|
|
55
|
+
return exports.dynamoDb;
|
|
32
56
|
};
|
|
33
57
|
exports.setDynamo = setDynamo;
|
|
34
58
|
exports.dynamoDb = (0, exports.setDynamo)('ap-southeast-2');
|
|
35
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
36
59
|
const putDynamo = (item, tableName, opt) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
-
|
|
60
|
+
const params = new lib_dynamodb_1.PutCommand(Object.assign({ TableName: tableName, Item: item }, ((opt === null || opt === void 0 ? void 0 : opt.pkName) && {
|
|
38
61
|
ConditionExpression: `attribute_not_exists(${opt.pkName})`,
|
|
39
62
|
})));
|
|
40
|
-
(0, log_1.debug)(`running dynamo put=${JSON.stringify(params, null, 2)}`);
|
|
41
63
|
try {
|
|
42
|
-
yield exports.dynamoDb.send(params);
|
|
43
|
-
return {};
|
|
64
|
+
yield withRetry(() => exports.dynamoDb.send(params), 'putDynamo');
|
|
65
|
+
return { data: undefined };
|
|
44
66
|
}
|
|
45
67
|
catch (e) {
|
|
46
|
-
(0, log_1.warn)('putDynamo error', e);
|
|
47
68
|
return { error: e.toString() };
|
|
48
69
|
}
|
|
49
70
|
});
|
|
50
71
|
exports.putDynamo = putDynamo;
|
|
51
|
-
|
|
52
|
-
const batchWrite = (tableName, itemsIn) => __awaiter(void 0, void 0, void 0, function* () {
|
|
53
|
-
//batch up to 20, so we can retry.
|
|
54
|
-
let chunked = (0, array_1.chunk)(itemsIn, 20);
|
|
72
|
+
const batchWrite = (tableName, items) => __awaiter(void 0, void 0, void 0, function* () {
|
|
55
73
|
try {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const retryMax = 3;
|
|
74
|
+
const chunked = (0, array_1.chunk)(items, 20);
|
|
75
|
+
yield (0, async_1.asyncForEach)(chunked, (chunk) => __awaiter(void 0, void 0, void 0, function* () {
|
|
59
76
|
const params = new lib_dynamodb_1.BatchWriteCommand({
|
|
60
77
|
RequestItems: {
|
|
61
|
-
[
|
|
62
|
-
PutRequest: { Item },
|
|
63
|
-
})),
|
|
78
|
+
[tableName]: chunk.map((Item) => ({ PutRequest: { Item } })),
|
|
64
79
|
},
|
|
65
80
|
});
|
|
66
|
-
(
|
|
67
|
-
// eslint-disable-next-line
|
|
68
|
-
while (true) {
|
|
69
|
-
try {
|
|
70
|
-
yield exports.dynamoDb.send(params);
|
|
71
|
-
return {};
|
|
72
|
-
}
|
|
73
|
-
catch (e) {
|
|
74
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
75
|
-
const es = e.toString();
|
|
76
|
-
let msg = es;
|
|
77
|
-
(0, log_1.warn)('dynamo write error', msg);
|
|
78
|
-
if (es.indexOf('429') !== -1 ||
|
|
79
|
-
es.indexOf('ProvisionedThroughputExceeded') !== -1) {
|
|
80
|
-
retryCount += 1;
|
|
81
|
-
msg = `batch write throttled. retry ${retryCount}/${retryMax}`;
|
|
82
|
-
(0, log_1.warn)(msg);
|
|
83
|
-
if (retryCount >= retryMax) {
|
|
84
|
-
throw new Error(`Max retries (${retryMax}) exceeded: ${es}`);
|
|
85
|
-
}
|
|
86
|
-
yield (0, sleep_1.sleep)(2000);
|
|
87
|
-
// Continue the while loop to retry
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
// For non-throttling errors, throw immediately
|
|
91
|
-
throw e;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
81
|
+
yield withRetry(() => exports.dynamoDb.send(params), 'batchWrite');
|
|
94
82
|
}));
|
|
95
|
-
return {};
|
|
83
|
+
return { data: undefined };
|
|
96
84
|
}
|
|
97
85
|
catch (e) {
|
|
98
|
-
(0, log_1.warn)('batchWrite error', e);
|
|
99
86
|
return { error: e.toString() };
|
|
100
87
|
}
|
|
101
88
|
});
|
|
102
89
|
exports.batchWrite = batchWrite;
|
|
103
|
-
const batchDelete = (
|
|
104
|
-
// batch up to 20, so we can retry
|
|
105
|
-
let chunked = (0, array_1.chunk)(keys, 20);
|
|
90
|
+
const batchDelete = (params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
106
91
|
try {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
const params = new lib_dynamodb_1.BatchWriteCommand({
|
|
92
|
+
const chunked = (0, array_1.chunk)(params.keys, 20);
|
|
93
|
+
yield (0, async_1.asyncForEach)(chunked, (chunk) => __awaiter(void 0, void 0, void 0, function* () {
|
|
94
|
+
const command = new lib_dynamodb_1.BatchWriteCommand({
|
|
111
95
|
RequestItems: {
|
|
112
|
-
[
|
|
113
|
-
DeleteRequest: { Key: { [
|
|
96
|
+
[params.tableName]: chunk.map((key) => ({
|
|
97
|
+
DeleteRequest: { Key: { [params.pkName]: key } },
|
|
114
98
|
})),
|
|
115
99
|
},
|
|
116
100
|
});
|
|
117
|
-
(
|
|
118
|
-
while (retryCount < retryMax) {
|
|
119
|
-
try {
|
|
120
|
-
yield exports.dynamoDb.send(params);
|
|
121
|
-
return {};
|
|
122
|
-
}
|
|
123
|
-
catch (e) {
|
|
124
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
125
|
-
const es = e.toString();
|
|
126
|
-
let shouldRetry = false;
|
|
127
|
-
if (es.indexOf('429') !== -1 ||
|
|
128
|
-
es.indexOf('ProvisionedThroughputExceeded') !== -1) {
|
|
129
|
-
shouldRetry = true;
|
|
130
|
-
retryCount += 1;
|
|
131
|
-
const msg = `batch delete write throttled. retry ${retryCount}/${retryMax}`;
|
|
132
|
-
(0, log_1.warn)('dynamo write error', msg);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
// Non-retryable error
|
|
136
|
-
throw e;
|
|
137
|
-
}
|
|
138
|
-
if (shouldRetry) {
|
|
139
|
-
if (retryCount >= retryMax) {
|
|
140
|
-
(0, log_1.warn)(`Max retries (${retryMax}) reached, giving up`);
|
|
141
|
-
throw e;
|
|
142
|
-
}
|
|
143
|
-
(0, log_1.warn)(`dynamo retry ${retryCount}/${retryMax}`);
|
|
144
|
-
yield (0, sleep_1.sleep)(2000 * Math.pow(2, retryCount - 1)); // Exponential backoff
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
101
|
+
yield withRetry(() => exports.dynamoDb.send(command), 'batchDelete');
|
|
149
102
|
}));
|
|
150
|
-
return {};
|
|
103
|
+
return { data: undefined };
|
|
151
104
|
}
|
|
152
105
|
catch (e) {
|
|
153
|
-
(0, log_1.warn)('batchDelete error', e);
|
|
154
106
|
return { error: e.toString() };
|
|
155
107
|
}
|
|
156
108
|
});
|
|
157
109
|
exports.batchDelete = batchDelete;
|
|
158
|
-
const scan = (tableName,
|
|
110
|
+
const scan = (tableName, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
111
|
+
var _a, _b;
|
|
159
112
|
try {
|
|
113
|
+
const Items = [];
|
|
160
114
|
let ExclusiveStartKey;
|
|
161
|
-
|
|
115
|
+
const projectionAttrs = (_a = options === null || options === void 0 ? void 0 : options.requiredAttributeList) === null || _a === void 0 ? void 0 : _a.reduce((acc, attr, index) => {
|
|
116
|
+
acc[`#proj${index}`] = attr;
|
|
117
|
+
return acc;
|
|
118
|
+
}, {});
|
|
119
|
+
const expressionAttributeNames = Object.assign(Object.assign({}, projectionAttrs), (_b = options === null || options === void 0 ? void 0 : options.filter) === null || _b === void 0 ? void 0 : _b.attrNames);
|
|
162
120
|
do {
|
|
163
|
-
|
|
164
|
-
ExpressionAttributeValues:
|
|
165
|
-
})))), ((
|
|
166
|
-
|
|
167
|
-
})),
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
121
|
+
const params = new lib_dynamodb_1.ScanCommand(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ TableName: tableName }, ((options === null || options === void 0 ? void 0 : options.filter) && Object.assign({ FilterExpression: options.filter.filterExpression }, (options.filter.attrValues && {
|
|
122
|
+
ExpressionAttributeValues: options.filter.attrValues,
|
|
123
|
+
})))), (Object.keys(expressionAttributeNames).length > 0 && {
|
|
124
|
+
ExpressionAttributeNames: expressionAttributeNames,
|
|
125
|
+
})), ((options === null || options === void 0 ? void 0 : options.requiredAttributeList) && {
|
|
126
|
+
ProjectionExpression: options.requiredAttributeList
|
|
127
|
+
.map((_, index) => `#proj${index}`)
|
|
128
|
+
.join(', '),
|
|
129
|
+
})), { ExclusiveStartKey }), ((options === null || options === void 0 ? void 0 : options.limit) &&
|
|
130
|
+
Items.length < options.limit && {
|
|
131
|
+
Limit: options.limit - Items.length,
|
|
132
|
+
})));
|
|
133
|
+
const result = yield withRetry(() => exports.dynamoDb.send(params), 'scan');
|
|
134
|
+
if (result.Items) {
|
|
135
|
+
Items.push(...result.Items);
|
|
175
136
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
return {
|
|
137
|
+
ExclusiveStartKey = result.LastEvaluatedKey;
|
|
138
|
+
if ((options === null || options === void 0 ? void 0 : options.limit) && Items.length >= options.limit) {
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
} while (ExclusiveStartKey);
|
|
142
|
+
return {
|
|
143
|
+
data: (options === null || options === void 0 ? void 0 : options.limit) ? Items.slice(0, options.limit) : Items,
|
|
144
|
+
};
|
|
182
145
|
}
|
|
183
146
|
catch (e) {
|
|
184
|
-
(0, log_1.warn)('scan error:', e);
|
|
185
147
|
return { error: e.toString() };
|
|
186
148
|
}
|
|
187
149
|
});
|
|
188
150
|
exports.scan = scan;
|
|
189
|
-
const getItemsDynamo = (
|
|
151
|
+
const getItemsDynamo = (params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
190
152
|
var _c, _d;
|
|
191
|
-
const params = new lib_dynamodb_1.BatchGetCommand({
|
|
192
|
-
RequestItems: {
|
|
193
|
-
[tableName]: {
|
|
194
|
-
Keys: items.map(({ pkName, pkValue }) => ({
|
|
195
|
-
[pkName]: pkValue,
|
|
196
|
-
})),
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
153
|
try {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
154
|
+
const command = new lib_dynamodb_1.BatchGetCommand({
|
|
155
|
+
RequestItems: {
|
|
156
|
+
[params.tableName]: {
|
|
157
|
+
Keys: params.items.map(({ pkName, pkValue }) => ({
|
|
158
|
+
[pkName]: pkValue,
|
|
159
|
+
})),
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
const result = yield withRetry(() => exports.dynamoDb.send(command), 'getItemsDynamo');
|
|
164
|
+
return {
|
|
165
|
+
data: (_d = (_c = result.Responses) === null || _c === void 0 ? void 0 : _c[params.tableName]) !== null && _d !== void 0 ? _d : [],
|
|
166
|
+
};
|
|
204
167
|
}
|
|
205
168
|
catch (e) {
|
|
206
|
-
(0, log_1.warn)('getItemsDynamo error:', e);
|
|
207
169
|
return { error: e.toString() };
|
|
208
|
-
//
|
|
209
170
|
}
|
|
210
171
|
});
|
|
211
172
|
exports.getItemsDynamo = getItemsDynamo;
|
|
212
|
-
const getItemDynamo = (
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
173
|
+
const getItemDynamo = (params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
174
|
+
const result = yield (0, exports.getItemsDynamo)({
|
|
175
|
+
tableName: params.tableName,
|
|
176
|
+
items: [{ pkName: params.pkName, pkValue: params.pkValue }],
|
|
177
|
+
});
|
|
178
|
+
if (isError(result)) {
|
|
179
|
+
return result;
|
|
216
180
|
}
|
|
217
|
-
return { data:
|
|
181
|
+
return { data: result.data[0] };
|
|
218
182
|
});
|
|
219
183
|
exports.getItemDynamo = getItemDynamo;
|
|
220
|
-
const queryDynamo = (
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
184
|
+
const queryDynamo = (params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
185
|
+
var _e, _f, _g;
|
|
186
|
+
try {
|
|
187
|
+
let kce = `#${params.pkName.toLowerCase()} ${(_e = params.pkOperator) !== null && _e !== void 0 ? _e : '='} :${params.pkName.toLowerCase()}`;
|
|
188
|
+
const ean = {
|
|
189
|
+
[`#${params.pkName.toLowerCase()}`]: params.pkName,
|
|
190
|
+
};
|
|
191
|
+
const eav = {
|
|
192
|
+
[`:${params.pkName.toLowerCase()}`]: params.pkValue,
|
|
193
|
+
};
|
|
194
|
+
if (params.skName && params.skValue !== undefined) {
|
|
195
|
+
const { skName, skValue, skOperator = '=' } = params;
|
|
196
|
+
if (skOperator === 'BETWEEN' && Array.isArray(skValue)) {
|
|
197
|
+
const [start, end] = skValue;
|
|
198
|
+
kce += ` AND #${skName.toLowerCase()} BETWEEN :${skName}1 AND :${skName}2`;
|
|
199
|
+
ean[`#${skName.toLowerCase()}`] = skName;
|
|
200
|
+
eav[`:${skName}1`] = start;
|
|
201
|
+
eav[`:${skName}2`] = end;
|
|
202
|
+
}
|
|
203
|
+
else if (skOperator === 'BEGINS_WITH') {
|
|
204
|
+
kce += ` AND begins_with(#${skName.toLowerCase()}, :${skName.toLowerCase()})`;
|
|
205
|
+
ean[`#${skName.toLowerCase()}`] = skName;
|
|
206
|
+
eav[`:${skName.toLowerCase()}`] = skValue;
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
kce += ` AND #${skName.toLowerCase()} ${skOperator} :${skName.toLowerCase()}`;
|
|
210
|
+
ean[`#${skName.toLowerCase()}`] = skName;
|
|
211
|
+
eav[`:${skName.toLowerCase()}`] = skValue;
|
|
212
|
+
}
|
|
245
213
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
ean[`#${
|
|
249
|
-
|
|
250
|
-
|
|
214
|
+
let FilterExpression;
|
|
215
|
+
if (params.filterName && params.filterValue !== undefined) {
|
|
216
|
+
ean[`#${params.filterName.toLowerCase()}`] = params.filterName;
|
|
217
|
+
eav[`:${params.filterName.toLowerCase()}`] = params.filterValue;
|
|
218
|
+
FilterExpression =
|
|
219
|
+
params.filterOperator === 'contains'
|
|
220
|
+
? `contains(#${params.filterName.toLowerCase()}, :${params.filterName.toLowerCase()})`
|
|
221
|
+
: `#${params.filterName.toLowerCase()} ${(_f = params.filterOperator) !== null && _f !== void 0 ? _f : '='} :${params.filterName.toLowerCase()}`;
|
|
251
222
|
}
|
|
223
|
+
const items = [];
|
|
224
|
+
let { startKey } = params;
|
|
225
|
+
do {
|
|
226
|
+
const queryParams = new lib_dynamodb_1.QueryCommand({
|
|
227
|
+
TableName: params.tableName,
|
|
228
|
+
KeyConditionExpression: kce,
|
|
229
|
+
ExpressionAttributeNames: ean,
|
|
230
|
+
ExpressionAttributeValues: eav,
|
|
231
|
+
ScanIndexForward: (_g = params.sortAscending) !== null && _g !== void 0 ? _g : true,
|
|
232
|
+
Limit: params.limit,
|
|
233
|
+
IndexName: params.indexName,
|
|
234
|
+
ExclusiveStartKey: startKey,
|
|
235
|
+
FilterExpression,
|
|
236
|
+
});
|
|
237
|
+
const result = yield withRetry(() => exports.dynamoDb.send(queryParams), 'queryDynamo');
|
|
238
|
+
if (result.Items) {
|
|
239
|
+
items.push(...result.Items);
|
|
240
|
+
}
|
|
241
|
+
startKey = result.LastEvaluatedKey;
|
|
242
|
+
if (params.limit && items.length >= params.limit) {
|
|
243
|
+
return {
|
|
244
|
+
data: items.slice(0, params.limit),
|
|
245
|
+
startKey,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
} while (startKey && Object.keys(startKey).length > 0);
|
|
249
|
+
return { data: items };
|
|
252
250
|
}
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
ean[`#${filterName.toLowerCase()}`] = filterName;
|
|
256
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
257
|
-
eav[`:${filterName.toLowerCase()}`] = filterValue;
|
|
258
|
-
FilterExpression = `#${filterName.toLowerCase()} ${filterOperator} :${filterName.toLowerCase()}`;
|
|
259
|
-
if (filterOperator === 'contains') {
|
|
260
|
-
FilterExpression = `contains(#${filterName.toLowerCase()}, :${filterName.toLowerCase()})`;
|
|
261
|
-
}
|
|
251
|
+
catch (e) {
|
|
252
|
+
return { error: e.toString() };
|
|
262
253
|
}
|
|
263
|
-
const Items = [];
|
|
264
|
-
do {
|
|
265
|
-
const params = new lib_dynamodb_1.QueryCommand(Object.assign(Object.assign(Object.assign(Object.assign({ TableName: tableName, KeyConditionExpression: kce, ExpressionAttributeNames: ean, ExpressionAttributeValues: eav, ScanIndexForward: sortAscending }, (limit !== null && { Limit: limit || 1000 })), (indexName && { IndexName: indexName })), (startKey && {
|
|
266
|
-
ExclusiveStartKey: startKey,
|
|
267
|
-
})), (FilterExpression && { FilterExpression })));
|
|
268
|
-
let lek;
|
|
269
|
-
let newItems;
|
|
270
|
-
try {
|
|
271
|
-
({
|
|
272
|
-
Items: newItems,
|
|
273
|
-
LastEvaluatedKey: lek,
|
|
274
|
-
// eslint-disable-next-line no-await-in-loop
|
|
275
|
-
} = yield exports.dynamoDb.send(params));
|
|
276
|
-
if (newItems) {
|
|
277
|
-
Items.push(...newItems.map((i) => i));
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
catch (e) {
|
|
281
|
-
(0, log_1.warn)('error. query params=', JSON.stringify(params), e);
|
|
282
|
-
return { error: e.toString() };
|
|
283
|
-
}
|
|
284
|
-
startKey = lek;
|
|
285
|
-
(0, log_1.debug)(`dynamo query against ${params.input.TableName} ok, count=${newItems === null || newItems === void 0 ? void 0 : newItems.length} ${JSON.stringify(params)}`, ` next startkey=${startKey}`);
|
|
286
|
-
if (!!limit && Items.length > limit) {
|
|
287
|
-
return { data: Items, startKey };
|
|
288
|
-
}
|
|
289
|
-
} while (startKey && Object.keys(startKey).length > 0);
|
|
290
|
-
return { data: Items };
|
|
291
254
|
});
|
|
292
255
|
exports.queryDynamo = queryDynamo;
|
|
293
|
-
const getDynamoTtlDays = (days) => Math.ceil(
|
|
256
|
+
const getDynamoTtlDays = (days) => Math.ceil(Date.now() / 1000) + days * 86400;
|
|
294
257
|
exports.getDynamoTtlDays = getDynamoTtlDays;
|
|
295
|
-
const getDynamoTtlMinutes = (
|
|
258
|
+
const getDynamoTtlMinutes = (minutes) => Math.ceil(Date.now() / 1000) + minutes * 60;
|
|
296
259
|
exports.getDynamoTtlMinutes = getDynamoTtlMinutes;
|
|
297
260
|
const wipeTable = (tableName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
261
|
+
var _h, _j, _k;
|
|
298
262
|
try {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
// @ts-ignore
|
|
302
|
-
let keyHash = infoV.Table.KeySchema.find((k) => k.KeyType === 'HASH').AttributeName;
|
|
263
|
+
const info = yield withRetry(() => exports.dynamoDb.send(new client_dynamodb_1.DescribeTableCommand({ TableName: tableName })), 'wipeTable-describe');
|
|
264
|
+
const keyHash = (_k = (_j = (_h = info.Table) === null || _h === void 0 ? void 0 : _h.KeySchema) === null || _j === void 0 ? void 0 : _j.find((k) => k.KeyType === 'HASH')) === null || _k === void 0 ? void 0 : _k.AttributeName;
|
|
303
265
|
if (!keyHash) {
|
|
304
|
-
throw new Error('
|
|
305
|
-
}
|
|
306
|
-
let allraw = yield (0, exports.scan)(tableName);
|
|
307
|
-
if ('error' in allraw) {
|
|
308
|
-
throw allraw.error;
|
|
266
|
+
throw new Error('Could not find hash key');
|
|
309
267
|
}
|
|
310
268
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
311
|
-
|
|
312
|
-
(
|
|
269
|
+
const scanResult = yield (0, exports.scan)(tableName);
|
|
270
|
+
if (isError(scanResult)) {
|
|
271
|
+
throw new Error(scanResult.error);
|
|
272
|
+
}
|
|
313
273
|
yield (0, exports.batchDelete)({
|
|
314
274
|
tableName,
|
|
315
|
-
keys:
|
|
316
|
-
pkName:
|
|
275
|
+
keys: scanResult.data.map((item) => item[keyHash]),
|
|
276
|
+
pkName: keyHash,
|
|
317
277
|
});
|
|
318
|
-
|
|
319
|
-
return {};
|
|
278
|
+
return { data: undefined };
|
|
320
279
|
}
|
|
321
280
|
catch (e) {
|
|
322
|
-
(0, log_1.warn)('wipeTable error:', e);
|
|
323
281
|
return { error: e.toString() };
|
|
324
282
|
}
|
|
325
283
|
});
|
|
326
284
|
exports.wipeTable = wipeTable;
|
|
327
|
-
|
|
328
|
-
const getDynamoUpdates = (item, opt) => {
|
|
285
|
+
const getDynamoUpdates = (item, options) => {
|
|
329
286
|
var _a;
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
let UpdateExpression = `SET `;
|
|
287
|
+
const excludeKeys = ((_a = options === null || options === void 0 ? void 0 : options.excludeKeys) !== null && _a !== void 0 ? _a : ['PK']).map((k) => k.toLowerCase());
|
|
288
|
+
const validEntries = Object.entries(item).filter(([key, value]) => !excludeKeys.includes(key.toLowerCase()) && value != null);
|
|
333
289
|
const ExpressionAttributeNames = {};
|
|
334
290
|
const ExpressionAttributeValues = {};
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
UpdateExpression += `#${k} = :${k}, `;
|
|
341
|
-
ExpressionAttributeNames[`#${k}`] = k;
|
|
342
|
-
ExpressionAttributeValues[`:${k}`] = v;
|
|
343
|
-
});
|
|
291
|
+
const UpdateExpression = validEntries.reduce((expr, [key, value], index) => {
|
|
292
|
+
ExpressionAttributeNames[`#${key}`] = key;
|
|
293
|
+
ExpressionAttributeValues[`:${key}`] = value;
|
|
294
|
+
return `${expr}${index > 0 ? ', ' : ''}#${key} = :${key}`;
|
|
295
|
+
}, 'SET ');
|
|
344
296
|
return {
|
|
345
|
-
UpdateExpression
|
|
297
|
+
UpdateExpression,
|
|
346
298
|
ExpressionAttributeNames,
|
|
347
299
|
ExpressionAttributeValues,
|
|
348
300
|
ReturnValues: 'UPDATED_NEW',
|
package/package.json
CHANGED