ag-common 0.0.724 → 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.
@@ -1,77 +1,80 @@
1
1
  import { DynamoDBDocument } from '@aws-sdk/lib-dynamodb';
2
2
  import type { AwsCredentialIdentity } from '@smithy/types';
3
- import type { IQueryDynamo, Key } from '../types';
4
- export declare const setDynamo: (region: string, credentials?: AwsCredentialIdentity) => DynamoDBDocument;
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 putDynamo: <T extends Record<string, any>>(item: T, tableName: string, opt?: {
7
- /** if provided, will assert this PK value doesnt already exist */
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
- error?: string;
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
- error?: string;
21
- }>;
22
- export declare const scan: <T>(tableName: string, opt?: {
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
- tableName: string;
52
- }) => Promise<{
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: (mins: number) => number;
65
- export declare const wipeTable: (tableName: string) => Promise<{
66
- error?: string;
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, string | number | boolean>;
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,352 +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.dynamoDb = exports.setDynamo = void 0;
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 trim_1 = require("../../common/helpers/string/trim");
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
- let raw = new client_dynamodb_1.DynamoDBClient({ region, credentials });
27
- const ddbDocClient = lib_dynamodb_1.DynamoDBDocument.from(raw, {
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 = ddbDocClient;
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
- let params = new lib_dynamodb_1.PutCommand(Object.assign({ TableName: tableName, Item: item }, ((opt === null || opt === void 0 ? void 0 : opt.pkName) && {
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
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
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
- yield (0, async_1.asyncForEach)(chunked, (items) => __awaiter(void 0, void 0, void 0, function* () {
57
- let retryCount = 0;
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
- [`${tableName}`]: items.map((Item) => ({
62
- PutRequest: { Item },
63
- })),
78
+ [tableName]: chunk.map((Item) => ({ PutRequest: { Item } })),
64
79
  },
65
80
  });
66
- (0, log_1.debug)(`running dynamo batchWrite=${JSON.stringify(params, null, 2)}`);
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 = (_a) => __awaiter(void 0, [_a], void 0, function* ({ tableName, keys, pkName, }) {
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
- yield (0, async_1.asyncForEach)(chunked, (items) => __awaiter(void 0, void 0, void 0, function* () {
108
- let retryCount = 0;
109
- const retryMax = 3;
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
- [`${tableName}`]: items.map((key) => ({
113
- DeleteRequest: { Key: { [`${pkName}`]: key } },
96
+ [params.tableName]: chunk.map((key) => ({
97
+ DeleteRequest: { Key: { [params.pkName]: key } },
114
98
  })),
115
99
  },
116
100
  });
117
- (0, log_1.debug)(`running dynamo batch delete=${JSON.stringify(params, null, 2)}`);
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, opt) => __awaiter(void 0, void 0, void 0, function* () {
159
- var _b, _c;
110
+ const scan = (tableName, options) => __awaiter(void 0, void 0, void 0, function* () {
111
+ var _a, _b;
160
112
  try {
113
+ const Items = [];
161
114
  let ExclusiveStartKey;
162
- let Items = [];
163
- // Handle projection attributes
164
- const projectionAttrs = (_b = opt === null || opt === void 0 ? void 0 : opt.requiredAttributeList) === null || _b === void 0 ? void 0 : _b.reduce((acc, attr, index) => {
165
- const escapedName = `#proj${index}`;
166
- acc[escapedName] = attr;
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;
167
117
  return acc;
168
118
  }, {});
169
- // Merge projection attribute names with filter attribute names
170
- const expressionAttributeNames = Object.assign(Object.assign({}, projectionAttrs), (_c = opt === null || opt === void 0 ? void 0 : opt.filter) === null || _c === void 0 ? void 0 : _c.attrNames);
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);
171
120
  do {
172
- const params = new lib_dynamodb_1.ScanCommand(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ TableName: tableName }, ((opt === null || opt === void 0 ? void 0 : opt.filter) && Object.assign({ FilterExpression: opt.filter.filterExpression }, (opt.filter.attrValues && {
173
- ExpressionAttributeValues: opt.filter.attrValues,
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,
174
123
  })))), (Object.keys(expressionAttributeNames).length > 0 && {
175
124
  ExpressionAttributeNames: expressionAttributeNames,
176
- })), ((opt === null || opt === void 0 ? void 0 : opt.requiredAttributeList) && {
177
- ProjectionExpression: opt.requiredAttributeList
125
+ })), ((options === null || options === void 0 ? void 0 : options.requiredAttributeList) && {
126
+ ProjectionExpression: options.requiredAttributeList
178
127
  .map((_, index) => `#proj${index}`)
179
128
  .join(', '),
180
- })), { ExclusiveStartKey }), (((opt === null || opt === void 0 ? void 0 : opt.limit) && Items.length < opt.limit) && {
181
- Limit: opt.limit - Items.length
129
+ })), { ExclusiveStartKey }), ((options === null || options === void 0 ? void 0 : options.limit) &&
130
+ Items.length < options.limit && {
131
+ Limit: options.limit - Items.length,
182
132
  })));
183
- (0, log_1.debug)(`running dynamo scan=${JSON.stringify(params, null, 2)}`);
184
- const { Items: newItems = [], LastEvaluatedKey, } = yield exports.dynamoDb.send(params);
185
- ExclusiveStartKey = LastEvaluatedKey;
186
- Items.push(...newItems);
187
- // Break the loop if we've reached the limit
188
- if ((opt === null || opt === void 0 ? void 0 : opt.limit) && Items.length >= opt.limit) {
133
+ const result = yield withRetry(() => exports.dynamoDb.send(params), 'scan');
134
+ if (result.Items) {
135
+ Items.push(...result.Items);
136
+ }
137
+ ExclusiveStartKey = result.LastEvaluatedKey;
138
+ if ((options === null || options === void 0 ? void 0 : options.limit) && Items.length >= options.limit) {
189
139
  break;
190
140
  }
191
141
  } while (ExclusiveStartKey);
192
- // Ensure we don't return more items than the limit
193
- if ((opt === null || opt === void 0 ? void 0 : opt.limit) && Items.length > opt.limit) {
194
- Items = Items.slice(0, opt.limit);
195
- }
196
- (0, log_1.debug)(`dynamo scan against ${tableName} ok, count=${Items.length}`);
197
- return { data: Items };
142
+ return {
143
+ data: (options === null || options === void 0 ? void 0 : options.limit) ? Items.slice(0, options.limit) : Items,
144
+ };
198
145
  }
199
146
  catch (e) {
200
- (0, log_1.warn)('scan error:', e);
201
147
  return { error: e.toString() };
202
148
  }
203
149
  });
204
150
  exports.scan = scan;
205
- const getItemsDynamo = (_d) => __awaiter(void 0, [_d], void 0, function* ({ tableName, items, }) {
206
- var _e, _f;
207
- const params = new lib_dynamodb_1.BatchGetCommand({
208
- RequestItems: {
209
- [tableName]: {
210
- Keys: items.map(({ pkName, pkValue }) => ({
211
- [pkName]: pkValue,
212
- })),
213
- },
214
- },
215
- });
151
+ const getItemsDynamo = (params) => __awaiter(void 0, void 0, void 0, function* () {
152
+ var _c, _d;
216
153
  try {
217
- let res = yield exports.dynamoDb.send(params);
218
- let data = (_f = (_e = res.Responses) === null || _e === void 0 ? void 0 : _e[tableName].map((r) => r)) !== null && _f !== void 0 ? _f : [];
219
- return { data };
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
+ };
220
167
  }
221
168
  catch (e) {
222
- (0, log_1.warn)('getItemsDynamo error:', e);
223
169
  return { error: e.toString() };
224
- //
225
170
  }
226
171
  });
227
172
  exports.getItemsDynamo = getItemsDynamo;
228
- const getItemDynamo = (_g) => __awaiter(void 0, [_g], void 0, function* ({ tableName, pkName, pkValue, }) {
229
- let r = yield (0, exports.getItemsDynamo)({ tableName, items: [{ pkName, pkValue }] });
230
- if ('error' in r) {
231
- return { error: r.error };
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;
232
180
  }
233
- return { data: r.data[0] };
181
+ return { data: result.data[0] };
234
182
  });
235
183
  exports.getItemDynamo = getItemDynamo;
236
- const queryDynamo = (_h) => __awaiter(void 0, [_h], void 0, function* ({ tableName, pkName, pkValue, pkOperator = '=', skName, skValue, skOperator = '=', indexName, limit = 1000, startKey, filterName, filterValue, filterOperator = '=', sortAscending = true, }) {
237
- let kce = `#${pkName.toLowerCase()} ${pkOperator} :${pkName.toLowerCase()}`;
238
- const ean = { [`#${pkName.toLowerCase()}`]: pkName };
239
- const eav = {
240
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
241
- [`:${pkName.toLowerCase()}`]: pkValue,
242
- };
243
- if (skName) {
244
- if (skOperator === 'BETWEEN') {
245
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
246
- let [sp0, sp1] = skValue;
247
- const skName1 = `${skName.toLowerCase()}1`;
248
- const skName2 = `${skName.toLowerCase()}2`;
249
- kce += ` and #${skName.toLowerCase()} ${skOperator} :${skName1.toLowerCase()} AND :${skName2.toLowerCase()}`;
250
- ean[`#${skName.toLowerCase()}`] = skName;
251
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
252
- eav[`:${skName1}`] = sp0;
253
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
254
- eav[`:${skName2}`] = sp1;
255
- }
256
- else if (skOperator === 'BEGINS_WITH') {
257
- kce += ` and ${skOperator.toLowerCase()}(#${skName.toLowerCase()}, :${skName.toLowerCase()})`;
258
- ean[`#${skName.toLowerCase()}`] = skName;
259
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
260
- eav[`:${skName.toLowerCase()}`] = skValue;
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
+ }
261
213
  }
262
- else {
263
- kce += ` and #${skName.toLowerCase()} ${skOperator} :${skName.toLowerCase()}`;
264
- ean[`#${skName.toLowerCase()}`] = skName;
265
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
266
- eav[`:${skName.toLowerCase()}`] = skValue;
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()}`;
267
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 };
268
250
  }
269
- let FilterExpression;
270
- if (filterName) {
271
- ean[`#${filterName.toLowerCase()}`] = filterName;
272
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
273
- eav[`:${filterName.toLowerCase()}`] = filterValue;
274
- FilterExpression = `#${filterName.toLowerCase()} ${filterOperator} :${filterName.toLowerCase()}`;
275
- if (filterOperator === 'contains') {
276
- FilterExpression = `contains(#${filterName.toLowerCase()}, :${filterName.toLowerCase()})`;
277
- }
251
+ catch (e) {
252
+ return { error: e.toString() };
278
253
  }
279
- const Items = [];
280
- do {
281
- 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 && {
282
- ExclusiveStartKey: startKey,
283
- })), (FilterExpression && { FilterExpression })));
284
- let lek;
285
- let newItems;
286
- try {
287
- ({
288
- Items: newItems,
289
- LastEvaluatedKey: lek,
290
- // eslint-disable-next-line no-await-in-loop
291
- } = yield exports.dynamoDb.send(params));
292
- if (newItems) {
293
- Items.push(...newItems.map((i) => i));
294
- }
295
- }
296
- catch (e) {
297
- (0, log_1.warn)('error. query params=', JSON.stringify(params), e);
298
- return { error: e.toString() };
299
- }
300
- startKey = lek;
301
- (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}`);
302
- if (!!limit && Items.length > limit) {
303
- return { data: Items, startKey };
304
- }
305
- } while (startKey && Object.keys(startKey).length > 0);
306
- return { data: Items };
307
254
  });
308
255
  exports.queryDynamo = queryDynamo;
309
- const getDynamoTtlDays = (days) => Math.ceil(new Date().getTime() / 1000) + days * 86400;
256
+ const getDynamoTtlDays = (days) => Math.ceil(Date.now() / 1000) + days * 86400;
310
257
  exports.getDynamoTtlDays = getDynamoTtlDays;
311
- const getDynamoTtlMinutes = (mins) => Math.ceil(new Date().getTime() / 1000) + mins * 60;
258
+ const getDynamoTtlMinutes = (minutes) => Math.ceil(Date.now() / 1000) + minutes * 60;
312
259
  exports.getDynamoTtlMinutes = getDynamoTtlMinutes;
313
260
  const wipeTable = (tableName) => __awaiter(void 0, void 0, void 0, function* () {
261
+ var _h, _j, _k;
314
262
  try {
315
- let infoV = yield exports.dynamoDb.send(new client_dynamodb_1.DescribeTableCommand({ TableName: tableName }));
316
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
317
- // @ts-ignore
318
- 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;
319
265
  if (!keyHash) {
320
- throw new Error('couldnt find keyHash');
321
- }
322
- let allraw = yield (0, exports.scan)(tableName);
323
- if ('error' in allraw) {
324
- throw allraw.error;
266
+ throw new Error('Could not find hash key');
325
267
  }
326
268
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
327
- let all = allraw.data.map((d) => d) || [];
328
- (0, log_1.warn)(`will delete ${all.length} items from ${tableName}`);
269
+ const scanResult = yield (0, exports.scan)(tableName);
270
+ if (isError(scanResult)) {
271
+ throw new Error(scanResult.error);
272
+ }
329
273
  yield (0, exports.batchDelete)({
330
274
  tableName,
331
- keys: all.map((s) => s[keyHash]),
332
- pkName: 'PK',
275
+ keys: scanResult.data.map((item) => item[keyHash]),
276
+ pkName: keyHash,
333
277
  });
334
- (0, log_1.warn)(`cleared table ${tableName}`);
335
- return {};
278
+ return { data: undefined };
336
279
  }
337
280
  catch (e) {
338
- (0, log_1.warn)('wipeTable error:', e);
339
281
  return { error: e.toString() };
340
282
  }
341
283
  });
342
284
  exports.wipeTable = wipeTable;
343
- /** gets all fields in dynamokeys, and moves them into update expressions. eg will turn item.yourFieldName, into a dynamo write into field "yourFieldName" */
344
- const getDynamoUpdates = (item, opt) => {
285
+ const getDynamoUpdates = (item, options) => {
345
286
  var _a;
346
- let ek = (_a = opt === null || opt === void 0 ? void 0 : opt.excludeKeys) !== null && _a !== void 0 ? _a : ['PK'];
347
- ek = ek.map((r) => r.toLowerCase());
348
- 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);
349
289
  const ExpressionAttributeNames = {};
350
290
  const ExpressionAttributeValues = {};
351
- //
352
- const cleanedKeys = Object.entries(item).filter(([k]) => !ek.includes(k.toLowerCase()));
353
- cleanedKeys
354
- .filter(([_k, v]) => v !== null && v !== undefined)
355
- .forEach(([k, v]) => {
356
- UpdateExpression += `#${k} = :${k}, `;
357
- ExpressionAttributeNames[`#${k}`] = k;
358
- ExpressionAttributeValues[`:${k}`] = v;
359
- });
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 ');
360
296
  return {
361
- UpdateExpression: (0, trim_1.trimSide)(UpdateExpression, false, ' ', ','),
297
+ UpdateExpression,
362
298
  ExpressionAttributeNames,
363
299
  ExpressionAttributeValues,
364
300
  ReturnValues: 'UPDATED_NEW',
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.724",
2
+ "version": "0.0.725",
3
3
  "name": "ag-common",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",