inlaweb-lib-dynamodb 1.0.14 → 1.0.16
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/index.js +20 -4
- package/index.ts +528 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -81,10 +81,21 @@ class DynamoLib {
|
|
|
81
81
|
async query(params) {
|
|
82
82
|
try {
|
|
83
83
|
const parameters = this.buildQueryParams(params);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
let allItems = [];
|
|
85
|
+
let lastEvaluatedKey;
|
|
86
|
+
do {
|
|
87
|
+
if (lastEvaluatedKey) {
|
|
88
|
+
parameters.ExclusiveStartKey = lastEvaluatedKey;
|
|
89
|
+
}
|
|
90
|
+
this.logger.debug(`Query: ${JSON.stringify(parameters)}`);
|
|
91
|
+
const response = await this.docClient.send(new lib_dynamodb_1.QueryCommand(parameters));
|
|
92
|
+
this.logger.debug(`Query Result: ${JSON.stringify(response)}`);
|
|
93
|
+
if (response.Items) {
|
|
94
|
+
allItems = allItems.concat(response.Items);
|
|
95
|
+
}
|
|
96
|
+
lastEvaluatedKey = response.LastEvaluatedKey;
|
|
97
|
+
} while (lastEvaluatedKey);
|
|
98
|
+
return allItems;
|
|
88
99
|
}
|
|
89
100
|
catch (error) {
|
|
90
101
|
this.logger.error(error.message);
|
|
@@ -183,6 +194,11 @@ class DynamoLib {
|
|
|
183
194
|
case "attribute_exists":
|
|
184
195
|
params.FilterExpression += `attribute_exists (#key${index})`;
|
|
185
196
|
break;
|
|
197
|
+
case "BETWEEN":
|
|
198
|
+
params.FilterExpression += `#key${index} ${searchParameter.filterOperator} :value${index} AND :value1${index}`;
|
|
199
|
+
params.ExpressionAttributeValues[`:value1${index}`] =
|
|
200
|
+
searchParameter.value1;
|
|
201
|
+
break;
|
|
186
202
|
default:
|
|
187
203
|
params.FilterExpression += `#key${index} ${searchParameter.filterOperator} :value${index}`;
|
|
188
204
|
break;
|
package/index.ts
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
2
|
+
import {
|
|
3
|
+
DynamoDBDocumentClient,
|
|
4
|
+
GetCommand,
|
|
5
|
+
PutCommand,
|
|
6
|
+
QueryCommand,
|
|
7
|
+
UpdateCommand,
|
|
8
|
+
BatchWriteCommand,
|
|
9
|
+
TransactWriteCommand,
|
|
10
|
+
DeleteCommand,
|
|
11
|
+
} from "@aws-sdk/lib-dynamodb";
|
|
12
|
+
import { Logger } from "@aws-lambda-powertools/logger";
|
|
13
|
+
import {
|
|
14
|
+
ParamsPut,
|
|
15
|
+
ParamsGet,
|
|
16
|
+
ParamsQuery,
|
|
17
|
+
ParamsUpdate,
|
|
18
|
+
ProjectionExpression,
|
|
19
|
+
SearchParameters,
|
|
20
|
+
KeyValue,
|
|
21
|
+
InputUpdate,
|
|
22
|
+
Operation,
|
|
23
|
+
} from "./commons/types";
|
|
24
|
+
import moment from "moment-timezone";
|
|
25
|
+
|
|
26
|
+
const templatesUpdateExpresion = {
|
|
27
|
+
SET: (atribute: string) => `#${atribute} = :${atribute},`,
|
|
28
|
+
ADD: (atribute: string) => `#${atribute} :${atribute},`,
|
|
29
|
+
REMOVE: (atribute: string) => `#${atribute},`,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export class DynamoLib {
|
|
33
|
+
private readonly client: DynamoDBClient;
|
|
34
|
+
private readonly docClient: DynamoDBDocumentClient;
|
|
35
|
+
private readonly logger: Logger;
|
|
36
|
+
|
|
37
|
+
constructor() {
|
|
38
|
+
this.client = new DynamoDBClient({
|
|
39
|
+
customUserAgent: "lib-dynamodb",
|
|
40
|
+
disableHostPrefix: true,
|
|
41
|
+
userAgentAppId: "lib-dynamodb",
|
|
42
|
+
});
|
|
43
|
+
this.docClient = DynamoDBDocumentClient.from(this.client);
|
|
44
|
+
this.logger = new Logger({
|
|
45
|
+
serviceName: "lib-dynamodb",
|
|
46
|
+
logLevel: "DEBUG",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async putItem(tableName: string, item: KeyValue): Promise<void> {
|
|
51
|
+
try {
|
|
52
|
+
const params: ParamsPut = {
|
|
53
|
+
TableName: tableName,
|
|
54
|
+
Item: item,
|
|
55
|
+
ReturnItemCollectionMetrics: "SIZE",
|
|
56
|
+
ReturnConsumedCapacity: "TOTAL",
|
|
57
|
+
};
|
|
58
|
+
this.logger.debug(`PutItem: ${JSON.stringify(params)}`);
|
|
59
|
+
const result = await this.docClient.send(new PutCommand(params));
|
|
60
|
+
this.logger.debug(`PutItem Result: ${JSON.stringify(result)}`);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
this.logger.error((error as Error).message);
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async getItem<T>(
|
|
68
|
+
tableName: string,
|
|
69
|
+
key: KeyValue,
|
|
70
|
+
projectionExpression?: string,
|
|
71
|
+
): Promise<T> {
|
|
72
|
+
try {
|
|
73
|
+
const params: ParamsGet = {
|
|
74
|
+
TableName: tableName,
|
|
75
|
+
Key: key,
|
|
76
|
+
ReturnConsumedCapacity: "TOTAL",
|
|
77
|
+
};
|
|
78
|
+
const projection = this.buildProjectionExpression(projectionExpression);
|
|
79
|
+
if (projection) {
|
|
80
|
+
params.ProjectionExpression = projection.projectionExpression;
|
|
81
|
+
params.ExpressionAttributeNames = projection.expressionAttributeNames;
|
|
82
|
+
}
|
|
83
|
+
this.logger.debug(`GetItem: ${JSON.stringify(params)}`);
|
|
84
|
+
const response = await this.docClient.send(new GetCommand(params));
|
|
85
|
+
this.logger.debug(`GetItem Result: ${JSON.stringify(response)}`);
|
|
86
|
+
return response.Item as T;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
this.logger.error((error as Error).message);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async updateItem<T>(params: InputUpdate): Promise<T> {
|
|
94
|
+
try {
|
|
95
|
+
const itemUpdate = this.createUpdateParams(params);
|
|
96
|
+
this.logger.debug(`UpdateItem: ${JSON.stringify(itemUpdate.Update)}`);
|
|
97
|
+
const result = await this.docClient.send(
|
|
98
|
+
new UpdateCommand(itemUpdate.Update),
|
|
99
|
+
);
|
|
100
|
+
this.logger.debug(`UpdateItem Result: ${JSON.stringify(result)}`);
|
|
101
|
+
return result.Attributes as T;
|
|
102
|
+
} catch (error) {
|
|
103
|
+
this.logger.error((error as Error).message);
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async query<T>(params: {
|
|
109
|
+
tableName: string;
|
|
110
|
+
searchParameters: SearchParameters;
|
|
111
|
+
permission?: string;
|
|
112
|
+
username?: string;
|
|
113
|
+
}): Promise<T[]> {
|
|
114
|
+
try {
|
|
115
|
+
const parameters: ParamsQuery = this.buildQueryParams(params);
|
|
116
|
+
let allItems: T[] = [];
|
|
117
|
+
let lastEvaluatedKey: KeyValue | undefined;
|
|
118
|
+
|
|
119
|
+
do {
|
|
120
|
+
if (lastEvaluatedKey) {
|
|
121
|
+
parameters.ExclusiveStartKey = lastEvaluatedKey;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.logger.debug(`Query: ${JSON.stringify(parameters)}`);
|
|
125
|
+
const response = await this.docClient.send(
|
|
126
|
+
new QueryCommand(parameters),
|
|
127
|
+
);
|
|
128
|
+
this.logger.debug(`Query Result: ${JSON.stringify(response)}`);
|
|
129
|
+
|
|
130
|
+
if (response.Items) {
|
|
131
|
+
allItems = allItems.concat(response.Items as T[]);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
lastEvaluatedKey = response.LastEvaluatedKey;
|
|
135
|
+
} while (lastEvaluatedKey);
|
|
136
|
+
|
|
137
|
+
return allItems;
|
|
138
|
+
} catch (error) {
|
|
139
|
+
this.logger.error((error as Error).message);
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async deleteItem(tableName: string, key: KeyValue): Promise<void> {
|
|
145
|
+
try {
|
|
146
|
+
const params: ParamsGet = {
|
|
147
|
+
TableName: tableName,
|
|
148
|
+
Key: key,
|
|
149
|
+
ReturnConsumedCapacity: "TOTAL",
|
|
150
|
+
};
|
|
151
|
+
this.logger.debug(`DeleteItem: ${JSON.stringify(params)}`);
|
|
152
|
+
const response = await this.docClient.send(new DeleteCommand(params));
|
|
153
|
+
this.logger.debug(`DeleteItem Result: ${JSON.stringify(response)}`);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
this.logger.error((error as Error).message);
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private buildQueryParams(params: {
|
|
161
|
+
tableName: string;
|
|
162
|
+
searchParameters: SearchParameters;
|
|
163
|
+
permission?: string;
|
|
164
|
+
username?: string;
|
|
165
|
+
}): ParamsQuery {
|
|
166
|
+
const projection = this.buildProjectionExpression(
|
|
167
|
+
params.searchParameters.projectionExpression,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
const parameters: ParamsQuery = {
|
|
171
|
+
TableName: params.tableName,
|
|
172
|
+
KeyConditionExpression: "",
|
|
173
|
+
ExpressionAttributeNames: projection?.expressionAttributeNames || {},
|
|
174
|
+
ExpressionAttributeValues: {},
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
if (projection) {
|
|
178
|
+
parameters.ProjectionExpression = projection.projectionExpression;
|
|
179
|
+
}
|
|
180
|
+
if (params.searchParameters.exclusiveStartKey) {
|
|
181
|
+
parameters.ExclusiveStartKey = params.searchParameters.exclusiveStartKey;
|
|
182
|
+
}
|
|
183
|
+
if (params.searchParameters.limit) {
|
|
184
|
+
parameters.Limit = params.searchParameters.limit;
|
|
185
|
+
}
|
|
186
|
+
if (params.searchParameters.scanIndexForward) {
|
|
187
|
+
parameters.ScanIndexForward = params.searchParameters.scanIndexForward;
|
|
188
|
+
}
|
|
189
|
+
if (params.searchParameters.indexName !== "") {
|
|
190
|
+
parameters.IndexName = params.searchParameters.indexName;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (params.permission && params.permission === "OWNS") {
|
|
194
|
+
params.searchParameters.parameters.push({
|
|
195
|
+
name: "creationUser",
|
|
196
|
+
value: params.username,
|
|
197
|
+
operator: "FILTER",
|
|
198
|
+
filterOperator: "=",
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
params.searchParameters.parameters.forEach((searchParameter, index) => {
|
|
203
|
+
this.buildExpressions(searchParameter, index, parameters);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
return parameters;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private buildExpressions(
|
|
210
|
+
searchParameter: KeyValue,
|
|
211
|
+
index: number,
|
|
212
|
+
params: ParamsQuery,
|
|
213
|
+
): void {
|
|
214
|
+
if (index !== 0 && searchParameter.operator !== "FILTER")
|
|
215
|
+
params.KeyConditionExpression += " and ";
|
|
216
|
+
|
|
217
|
+
switch (searchParameter.operator) {
|
|
218
|
+
case "begins_with":
|
|
219
|
+
params.KeyConditionExpression += `${searchParameter.operator}(#key${index}, :value${index})`;
|
|
220
|
+
break;
|
|
221
|
+
case "BETWEEN":
|
|
222
|
+
params.KeyConditionExpression += `#key${index} ${searchParameter.operator} :value${index} AND :value1${index}`;
|
|
223
|
+
params.ExpressionAttributeValues[`:value1${index}`] =
|
|
224
|
+
searchParameter.value1;
|
|
225
|
+
break;
|
|
226
|
+
case "FILTER":
|
|
227
|
+
this.buildFilterExpression(searchParameter, index, params);
|
|
228
|
+
break;
|
|
229
|
+
default:
|
|
230
|
+
params.KeyConditionExpression += `#key${index} ${searchParameter.operator} :value${index}`;
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
params.ExpressionAttributeNames[`#key${index}`] = searchParameter.name;
|
|
235
|
+
params.ExpressionAttributeValues[`:value${index}`] = searchParameter.value;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
private buildFilterExpression(
|
|
239
|
+
searchParameter: KeyValue,
|
|
240
|
+
index: number,
|
|
241
|
+
params: ParamsQuery,
|
|
242
|
+
): void {
|
|
243
|
+
if (params.FilterExpression) params.FilterExpression += " and ";
|
|
244
|
+
else params.FilterExpression = "";
|
|
245
|
+
|
|
246
|
+
switch (searchParameter.filterOperator) {
|
|
247
|
+
case "contains":
|
|
248
|
+
params.FilterExpression += `contains (#key${index}, :value${index})`;
|
|
249
|
+
break;
|
|
250
|
+
case "begins_with":
|
|
251
|
+
params.FilterExpression += `${searchParameter.filterOperator}(#key${index}, :value${index})`;
|
|
252
|
+
break;
|
|
253
|
+
case "attribute_not_exists":
|
|
254
|
+
params.FilterExpression += `attribute_not_exists (#key${index})`;
|
|
255
|
+
break;
|
|
256
|
+
case "attribute_exists":
|
|
257
|
+
params.FilterExpression += `attribute_exists (#key${index})`;
|
|
258
|
+
break;
|
|
259
|
+
case "BETWEEN":
|
|
260
|
+
params.FilterExpression += `#key${index} ${searchParameter.filterOperator} :value${index} AND :value1${index}`;
|
|
261
|
+
params.ExpressionAttributeValues[`:value1${index}`] =
|
|
262
|
+
searchParameter.value1;
|
|
263
|
+
break;
|
|
264
|
+
default:
|
|
265
|
+
params.FilterExpression += `#key${index} ${searchParameter.filterOperator} :value${index}`;
|
|
266
|
+
break;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private buildProjectionExpression(
|
|
271
|
+
projectionExpression: string | undefined,
|
|
272
|
+
): ProjectionExpression | undefined {
|
|
273
|
+
if (!projectionExpression) {
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
const fields = projectionExpression.split(",");
|
|
277
|
+
if (fields.length > 0) {
|
|
278
|
+
let projectionExpression = "";
|
|
279
|
+
const expressionAttributeNames: KeyValue = {};
|
|
280
|
+
fields.forEach((field) => {
|
|
281
|
+
projectionExpression += `#${field},`;
|
|
282
|
+
expressionAttributeNames[`#${field}`] = field;
|
|
283
|
+
});
|
|
284
|
+
projectionExpression = projectionExpression.slice(0, -1);
|
|
285
|
+
return { projectionExpression, expressionAttributeNames };
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async saveBatch(table: string, items: KeyValue[]): Promise<boolean> {
|
|
290
|
+
try {
|
|
291
|
+
const executions = this.createBatch(items);
|
|
292
|
+
for (let i = 0; i < executions.length; i++) {
|
|
293
|
+
const params = {
|
|
294
|
+
RequestItems: {
|
|
295
|
+
[table]: executions[i] as any,
|
|
296
|
+
},
|
|
297
|
+
ReturnConsumedCapacity: "TOTAL" as const,
|
|
298
|
+
};
|
|
299
|
+
this.logger.debug(`BatchWrite: ${JSON.stringify(params)}`);
|
|
300
|
+
const response = await this.docClient.send(
|
|
301
|
+
new BatchWriteCommand(params),
|
|
302
|
+
);
|
|
303
|
+
this.logger.debug(`BatchWrite Result: ${JSON.stringify(response)}`);
|
|
304
|
+
}
|
|
305
|
+
return true;
|
|
306
|
+
} catch (error) {
|
|
307
|
+
this.logger.error((error as Error).message);
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
private createBatch(items: KeyValue[]): KeyValue[] {
|
|
313
|
+
const executions: KeyValue[] = [];
|
|
314
|
+
const numberOfBacthInsertions = Math.ceil(items.length / 25);
|
|
315
|
+
for (let i = 0; i < numberOfBacthInsertions; i++) {
|
|
316
|
+
executions[i] = [];
|
|
317
|
+
}
|
|
318
|
+
items.forEach((item, index) => {
|
|
319
|
+
const currentIndex = Math.ceil((index + 1) / 25);
|
|
320
|
+
executions[currentIndex - 1].push({ PutRequest: { Item: item } });
|
|
321
|
+
});
|
|
322
|
+
return executions;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async writeTransactions(items: KeyValue[], limit: number): Promise<boolean> {
|
|
326
|
+
try {
|
|
327
|
+
const executions = this.createWriteTransactions(items, limit);
|
|
328
|
+
for (let i = 0; i < executions.length; i++) {
|
|
329
|
+
const params = {
|
|
330
|
+
TransactItems: executions[i],
|
|
331
|
+
ReturnConsumedCapacity: "TOTAL" as const,
|
|
332
|
+
};
|
|
333
|
+
this.logger.debug(`TransactWrite: ${JSON.stringify(params)}`);
|
|
334
|
+
const response = await this.docClient.send(
|
|
335
|
+
new TransactWriteCommand(params),
|
|
336
|
+
);
|
|
337
|
+
this.logger.debug(`TransactWrite Result: ${JSON.stringify(response)}`);
|
|
338
|
+
}
|
|
339
|
+
return true;
|
|
340
|
+
} catch (error) {
|
|
341
|
+
this.logger.error((error as Error).message);
|
|
342
|
+
throw error;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
createWriteTransactions(items: KeyValue[], limit: number): KeyValue[][] {
|
|
347
|
+
const executions: KeyValue[][] = [];
|
|
348
|
+
const numberOfBacthInsertions = Math.ceil(items.length / limit);
|
|
349
|
+
for (let i = 0; i < numberOfBacthInsertions; i++) {
|
|
350
|
+
executions[i] = [];
|
|
351
|
+
}
|
|
352
|
+
items.forEach((item, index) => {
|
|
353
|
+
const currentIndex = Math.ceil((index + 1) / limit);
|
|
354
|
+
executions[currentIndex - 1].push(item);
|
|
355
|
+
});
|
|
356
|
+
return executions;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
createUpdateParams(params: InputUpdate): KeyValue {
|
|
360
|
+
const {
|
|
361
|
+
table,
|
|
362
|
+
PK,
|
|
363
|
+
SK,
|
|
364
|
+
item,
|
|
365
|
+
setAttributes,
|
|
366
|
+
addAttributes,
|
|
367
|
+
removeAttributes,
|
|
368
|
+
username,
|
|
369
|
+
} = params;
|
|
370
|
+
// Se crea el objeto de la operación
|
|
371
|
+
let itemUpdate = {
|
|
372
|
+
Update: {
|
|
373
|
+
TableName: table,
|
|
374
|
+
Key: { PK, SK },
|
|
375
|
+
UpdateExpression: ``,
|
|
376
|
+
ExpressionAttributeNames: {},
|
|
377
|
+
ExpressionAttributeValues: {},
|
|
378
|
+
ReturnConsumedCapacity: "TOTAL",
|
|
379
|
+
ReturnValues: "ALL_NEW",
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
// Se agregan los campos a modificar
|
|
383
|
+
if (Array.isArray(setAttributes) && setAttributes.length) {
|
|
384
|
+
this.formatUpdateExpression("SET", itemUpdate, item, setAttributes);
|
|
385
|
+
}
|
|
386
|
+
// Se agragan los campos nuevos del item
|
|
387
|
+
if (Array.isArray(addAttributes) && addAttributes.length) {
|
|
388
|
+
this.formatUpdateExpression("ADD", itemUpdate, item, addAttributes);
|
|
389
|
+
}
|
|
390
|
+
// Se agregan los campos que deben ser borrados
|
|
391
|
+
if (Array.isArray(removeAttributes) && removeAttributes.length) {
|
|
392
|
+
this.formatUpdateExpressionRemove(itemUpdate, removeAttributes);
|
|
393
|
+
}
|
|
394
|
+
// Se remueve el espacio al final de la expresión
|
|
395
|
+
itemUpdate.Update.UpdateExpression =
|
|
396
|
+
itemUpdate.Update.UpdateExpression.slice(0, -1);
|
|
397
|
+
return itemUpdate;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
private formatUpdateExpression(
|
|
401
|
+
operation: Operation,
|
|
402
|
+
updateObject: KeyValue,
|
|
403
|
+
item: KeyValue,
|
|
404
|
+
atributes: string[],
|
|
405
|
+
): void {
|
|
406
|
+
// Se agrega la operación.
|
|
407
|
+
updateObject.Update.UpdateExpression += `${operation} `;
|
|
408
|
+
// Se obtiene el templete de acuerdo a la operación.
|
|
409
|
+
let operationTemplate = templatesUpdateExpresion[operation];
|
|
410
|
+
// Se añaden los items afectados por la operación.
|
|
411
|
+
for (let atribute of atributes) {
|
|
412
|
+
if (
|
|
413
|
+
typeof item[atribute] === "boolean" ||
|
|
414
|
+
typeof item[atribute] === "number" ||
|
|
415
|
+
item[atribute]
|
|
416
|
+
) {
|
|
417
|
+
updateObject.Update.UpdateExpression += operationTemplate(atribute);
|
|
418
|
+
updateObject.Update.ExpressionAttributeNames[`#${atribute}`] = atribute;
|
|
419
|
+
updateObject.Update.ExpressionAttributeValues[`:${atribute}`] =
|
|
420
|
+
item[atribute];
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// Se remueve la coma final para evitar errores con el SDK.
|
|
424
|
+
updateObject.Update.UpdateExpression =
|
|
425
|
+
updateObject.Update.UpdateExpression.slice(0, -1);
|
|
426
|
+
// Se añade un espacio para poder agregar nuevas operaciones.
|
|
427
|
+
updateObject.Update.UpdateExpression += " ";
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private formatUpdateExpressionRemove(
|
|
431
|
+
updateObject: KeyValue,
|
|
432
|
+
atributes: string[],
|
|
433
|
+
): void {
|
|
434
|
+
let operation: Operation = "REMOVE";
|
|
435
|
+
// Se agrega la operación.
|
|
436
|
+
updateObject.Update.UpdateExpression += `${operation} `;
|
|
437
|
+
// Se obtiene el templete de acuerdo a la operación.
|
|
438
|
+
let operationTemplate = templatesUpdateExpresion[operation];
|
|
439
|
+
// Se añaden los items afectados por la operación.
|
|
440
|
+
for (let atribute of atributes) {
|
|
441
|
+
updateObject.Update.UpdateExpression += operationTemplate(atribute);
|
|
442
|
+
updateObject.Update.ExpressionAttributeNames[`#${atribute}`] = atribute;
|
|
443
|
+
}
|
|
444
|
+
// Se remueve la coma final para evitar errores con el SDK.
|
|
445
|
+
updateObject.Update.UpdateExpression =
|
|
446
|
+
updateObject.Update.UpdateExpression.slice(0, -1);
|
|
447
|
+
// Se añade un espacio para poder agregar nuevas operaciones.
|
|
448
|
+
updateObject.Update.UpdateExpression += " ";
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
async getId(
|
|
452
|
+
table: string,
|
|
453
|
+
entity: string,
|
|
454
|
+
username: string,
|
|
455
|
+
quantity?: number,
|
|
456
|
+
): Promise<number> {
|
|
457
|
+
try {
|
|
458
|
+
let item = await this.getItem<KeyValue>(
|
|
459
|
+
table,
|
|
460
|
+
{ PK: "COUN", SK: entity },
|
|
461
|
+
"order",
|
|
462
|
+
);
|
|
463
|
+
if (!item) {
|
|
464
|
+
item = {
|
|
465
|
+
PK: "COUN",
|
|
466
|
+
SK: entity,
|
|
467
|
+
entity: "COUN",
|
|
468
|
+
order: 0,
|
|
469
|
+
creationUser: username,
|
|
470
|
+
creationDate: moment
|
|
471
|
+
.tz(new Date(), "America/Bogota")
|
|
472
|
+
.format("YYYY-MM-DD"),
|
|
473
|
+
};
|
|
474
|
+
await this.putItem(table, item);
|
|
475
|
+
}
|
|
476
|
+
const params: ParamsUpdate = {
|
|
477
|
+
TableName: table,
|
|
478
|
+
Key: { PK: "COUN", SK: entity },
|
|
479
|
+
UpdateExpression: `SET #id = #id + :increment`,
|
|
480
|
+
ExpressionAttributeNames: { "#id": "order" },
|
|
481
|
+
ExpressionAttributeValues: { ":increment": quantity || 1 },
|
|
482
|
+
ReturnValues: "UPDATED_OLD",
|
|
483
|
+
};
|
|
484
|
+
this.logger.debug(`GetId: ${JSON.stringify(params)}`);
|
|
485
|
+
const result = await this.docClient.send(new UpdateCommand(params));
|
|
486
|
+
this.logger.debug(`GetId Result: ${JSON.stringify(result)}`);
|
|
487
|
+
if (result.Attributes) return result.Attributes.order + 1;
|
|
488
|
+
return 1;
|
|
489
|
+
} catch (error) {
|
|
490
|
+
this.logger.error((error as Error).message);
|
|
491
|
+
throw error;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
async validatePermission(
|
|
496
|
+
table: string,
|
|
497
|
+
entity: string,
|
|
498
|
+
action: string,
|
|
499
|
+
profile: string,
|
|
500
|
+
): Promise<string | undefined> {
|
|
501
|
+
try {
|
|
502
|
+
let result: KeyValue;
|
|
503
|
+
let searchParameters = {
|
|
504
|
+
indexName: "GSI2",
|
|
505
|
+
parameters: [
|
|
506
|
+
{ name: "entity", value: "PERM", operator: "=" },
|
|
507
|
+
{
|
|
508
|
+
name: "relation2",
|
|
509
|
+
value: `${profile}|${entity}|${action}`,
|
|
510
|
+
operator: "=",
|
|
511
|
+
},
|
|
512
|
+
],
|
|
513
|
+
};
|
|
514
|
+
let permissionQuery = await this.query<KeyValue>({
|
|
515
|
+
tableName: table,
|
|
516
|
+
searchParameters,
|
|
517
|
+
});
|
|
518
|
+
if (permissionQuery && permissionQuery.length > 0) {
|
|
519
|
+
result = permissionQuery[0];
|
|
520
|
+
return result.type === "ALL" ? "ALL" : "OWNS";
|
|
521
|
+
}
|
|
522
|
+
throw new Error("UNAUTHORIZE_REQUEST");
|
|
523
|
+
} catch (error) {
|
|
524
|
+
this.logger.error((error as Error).message);
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|