@izara_project/izara-core-library-find-data 1.0.1 → 1.0.2
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 +42 -0
- package/package.json +4 -5
- package/src/FindDataSharedLib.js +425 -0
package/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2021 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
// Import the Find Data shared library functions
|
|
21
|
+
const findDataSharedLib = require('./src/FindDataSharedLib');
|
|
22
|
+
|
|
23
|
+
// Export all the functions
|
|
24
|
+
module.exports = {
|
|
25
|
+
// Find Data ID Creation
|
|
26
|
+
createFindDataId: findDataSharedLib.createFindDataId,
|
|
27
|
+
|
|
28
|
+
// Find Data Status Management
|
|
29
|
+
checkFindDataMainStatus: findDataSharedLib.checkFindDataMainStatus,
|
|
30
|
+
completeFindDataMain: findDataSharedLib.completeFindDataMain,
|
|
31
|
+
sendFindDataCompleteMessage: findDataSharedLib.sendFindDataCompleteMessage,
|
|
32
|
+
|
|
33
|
+
// Awaiting Steps Management
|
|
34
|
+
createFindDataAwaitingStep: findDataSharedLib.createFindDataAwaitingStep,
|
|
35
|
+
findFindDataIdsAwaitingStep: findDataSharedLib.findFindDataIdsAwaitingStep,
|
|
36
|
+
removeFindDataAwaitingStep: findDataSharedLib.removeFindDataAwaitingStep,
|
|
37
|
+
|
|
38
|
+
// Sorted Requests Management
|
|
39
|
+
createFindDataSortedRequest: findDataSharedLib.createFindDataSortedRequest,
|
|
40
|
+
findFindDataSortedRequests: findDataSharedLib.findFindDataSortedRequests,
|
|
41
|
+
removeFindDataSortedRequest: findDataSharedLib.removeFindDataSortedRequest
|
|
42
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@izara_project/izara-core-library-find-data",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Shared find data logic",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -20,9 +20,8 @@
|
|
|
20
20
|
"testEnvironment": "node"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
+
"@izara_project/izara-core-library-core": "^1.0.15",
|
|
23
24
|
"@izara_project/izara-core-library-external-request": "^1.0.17",
|
|
24
|
-
"
|
|
25
|
-
"@izara_project/izara-shared": "^1.0.121",
|
|
26
|
-
"aws-jwt-verify": "^4.0.1"
|
|
25
|
+
"object-hash": "^3.0.0"
|
|
27
26
|
}
|
|
28
|
-
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright (C) 2021 Sven Mason <http://izara.io>
|
|
3
|
+
|
|
4
|
+
This program is free software: you can redistribute it and/or modify
|
|
5
|
+
it under the terms of the GNU Affero General Public License as
|
|
6
|
+
published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
License, or (at your option) any later version.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU Affero General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
'use strict';
|
|
19
|
+
|
|
20
|
+
// External library imports
|
|
21
|
+
const hash = require('object-hash');
|
|
22
|
+
|
|
23
|
+
// Izara core libraries
|
|
24
|
+
const { NoRetryError } = require('@izara_project/izara-core-library-core/src/NoRetryError');
|
|
25
|
+
const { sns } = require('@izara_project/izara-core-library-external-request');
|
|
26
|
+
const asyncFlowSharedLib = require("@izara_project/izara-core-library-asynchronous-flow");
|
|
27
|
+
const snsSharedLib = require('@izara_project/izara-core-library-sns');
|
|
28
|
+
const storedCacheSharedLib = require("@izara_project/izara-core-library-stored-cache");
|
|
29
|
+
|
|
30
|
+
// Commented out libraries that are not currently used
|
|
31
|
+
// const Logger = require('@izara_project/izara-core-library-logger');
|
|
32
|
+
// const dynamodbSharedLib = require('./DynamodbSharedLib');
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
module.exports.createFindDataId = (
|
|
36
|
+
fieldName,
|
|
37
|
+
objType,
|
|
38
|
+
identifiers,
|
|
39
|
+
requestProperties = {}
|
|
40
|
+
) => {
|
|
41
|
+
return hash({
|
|
42
|
+
fieldName: fieldName,
|
|
43
|
+
objType: objType,
|
|
44
|
+
identifiers: identifiers,
|
|
45
|
+
requestProperties: requestProperties
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Checks if existing FindDataMain exists, if it does check expired? if yes reset to processing
|
|
52
|
+
* @param {string} fieldName
|
|
53
|
+
* @param {string} objType
|
|
54
|
+
* @param {object} identifiers
|
|
55
|
+
*
|
|
56
|
+
* @returns {string} status "process"|"processing"|"complete" ("process" means requesting function needs to continue processing)
|
|
57
|
+
* if unable to reset expired record status to processing (because other thread changing record) throw NoRetryError
|
|
58
|
+
*/
|
|
59
|
+
module.exports.checkFindDataMainStatus = async (
|
|
60
|
+
_izContext,
|
|
61
|
+
fieldName,
|
|
62
|
+
objType,
|
|
63
|
+
identifiers,
|
|
64
|
+
requestProperties,
|
|
65
|
+
callingFlow = "",
|
|
66
|
+
removeAttributes = []
|
|
67
|
+
) => {
|
|
68
|
+
try {
|
|
69
|
+
|
|
70
|
+
const findDataId = this.createFindDataId(
|
|
71
|
+
fieldName,
|
|
72
|
+
objType,
|
|
73
|
+
identifiers,
|
|
74
|
+
requestProperties
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
let [cacheStatus, findDataMain] = await storedCacheSharedLib.checkStoredCacheStatus(
|
|
78
|
+
_izContext,
|
|
79
|
+
"FindDataMain", //dynamodbSharedLib.tableName('FindDataMain'), // ".. build table name from serviceName + FindDataMain",
|
|
80
|
+
{ // keyValues
|
|
81
|
+
findDataId: findDataId
|
|
82
|
+
},
|
|
83
|
+
{ // additionalAttributesWhenCreate
|
|
84
|
+
attributes: {
|
|
85
|
+
fieldName: fieldName,
|
|
86
|
+
objType: objType,
|
|
87
|
+
identifiers: identifiers,
|
|
88
|
+
requestProperties: requestProperties
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
'findData', // prefix
|
|
92
|
+
removeAttributes // removeAttributes
|
|
93
|
+
);
|
|
94
|
+
if (cacheStatus !== "process") {
|
|
95
|
+
// is either complete, processing by another thread, error, or some other status
|
|
96
|
+
// means this request should not continue to process the request
|
|
97
|
+
|
|
98
|
+
if (cacheStatus === "complete" || cacheStatus === "error") {
|
|
99
|
+
|
|
100
|
+
if (callingFlow) {
|
|
101
|
+
// send message to OutProcessLogical for complexFilter service or other calling flow knows this logical element is complete
|
|
102
|
+
await this.sendFindDataCompleteMessage(
|
|
103
|
+
_izContext,
|
|
104
|
+
fieldName,
|
|
105
|
+
objType,
|
|
106
|
+
identifiers,
|
|
107
|
+
requestProperties,
|
|
108
|
+
findDataMain.dataValue,
|
|
109
|
+
cacheStatus,
|
|
110
|
+
callingFlow
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return [cacheStatus, findDataId, findDataMain];
|
|
117
|
+
|
|
118
|
+
} catch (e) {
|
|
119
|
+
_izContext.logger.error('ERROR checkFindDataMainStatus:', e)
|
|
120
|
+
throw (e)
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* send message to OutFindDataComplete for searchResult service to know this requiredData is complete, and update FindDataMain
|
|
126
|
+
* @param {string} fieldName
|
|
127
|
+
* @param {object} objType
|
|
128
|
+
* @param {object} identifiers
|
|
129
|
+
*
|
|
130
|
+
*/
|
|
131
|
+
module.exports.completeFindDataMain = async (
|
|
132
|
+
_izContext,
|
|
133
|
+
fieldName,
|
|
134
|
+
objType,
|
|
135
|
+
identifiers,
|
|
136
|
+
requestProperties,
|
|
137
|
+
dataValue,
|
|
138
|
+
status,
|
|
139
|
+
errorsFound = []
|
|
140
|
+
) => {
|
|
141
|
+
|
|
142
|
+
//* validate status
|
|
143
|
+
if (status !== 'error' && status !== 'complete') {
|
|
144
|
+
throw new NoRetryError(`status: ${status} is not valided.`)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
let timeCacheComplete = Date.now()
|
|
148
|
+
|
|
149
|
+
// send out message first for idempotence
|
|
150
|
+
await this.sendFindDataCompleteMessage(
|
|
151
|
+
_izContext,
|
|
152
|
+
fieldName,
|
|
153
|
+
objType,
|
|
154
|
+
identifiers,
|
|
155
|
+
requestProperties,
|
|
156
|
+
dataValue,
|
|
157
|
+
status,
|
|
158
|
+
"",
|
|
159
|
+
errorsFound,
|
|
160
|
+
timeCacheComplete
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
//* update FindDataMain record set status = complete, dataValue = dataValue, expiryTime = ..., remove uniqueRequestId if exists
|
|
164
|
+
//* status = complete|error, if errorsFound has elements add as well
|
|
165
|
+
const findDataId = this.createFindDataId(
|
|
166
|
+
fieldName,
|
|
167
|
+
objType,
|
|
168
|
+
identifiers,
|
|
169
|
+
requestProperties
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
await storedCacheSharedLib.completeStoredCache(
|
|
173
|
+
_izContext,
|
|
174
|
+
"FindDataMain",
|
|
175
|
+
{ // keyValues
|
|
176
|
+
findDataId: findDataId
|
|
177
|
+
},
|
|
178
|
+
status,
|
|
179
|
+
{ // additionalAttributes
|
|
180
|
+
attributes: {
|
|
181
|
+
dataValue: dataValue
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
'findData', // prefix
|
|
185
|
+
null, // expiryInterval
|
|
186
|
+
timeCacheComplete,
|
|
187
|
+
errorsFound
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// const prefix = 'findData'
|
|
191
|
+
// let updateAttributes = [
|
|
192
|
+
// {
|
|
193
|
+
// attributeName: prefix + 'Status', // TOCHECK : prefix + "status" ??? same like cache
|
|
194
|
+
// action: "set",
|
|
195
|
+
// value: status,
|
|
196
|
+
// },
|
|
197
|
+
// {
|
|
198
|
+
// attributeName: prefix + 'ExpiryTime',
|
|
199
|
+
// action: "set",
|
|
200
|
+
// value: Date.now() + expiryInterval,
|
|
201
|
+
// },
|
|
202
|
+
// {
|
|
203
|
+
// attributeName: 'dataValue',
|
|
204
|
+
// action: "set",
|
|
205
|
+
// value: value,
|
|
206
|
+
// },
|
|
207
|
+
// {
|
|
208
|
+
// attributeName: prefix + 'UniqueRequestId',
|
|
209
|
+
// action: "remove",
|
|
210
|
+
// },
|
|
211
|
+
// ]
|
|
212
|
+
|
|
213
|
+
// if (status == 'error' && errorsFound.length > 0) {
|
|
214
|
+
// updateAttributes.push(
|
|
215
|
+
// {
|
|
216
|
+
// attributeName: prefix + 'ErrorsFound',
|
|
217
|
+
// action: "set",
|
|
218
|
+
// value: errorsFound,
|
|
219
|
+
// listAppend: true
|
|
220
|
+
// }
|
|
221
|
+
// )
|
|
222
|
+
// }
|
|
223
|
+
|
|
224
|
+
// await dynamodbSharedLib.updateItem(
|
|
225
|
+
// _izContext,
|
|
226
|
+
// dynamodbSharedLib.tableName('FindDataMain'),
|
|
227
|
+
// { [fieldName]: findDataId }, // keyValues
|
|
228
|
+
// updateAttributes,
|
|
229
|
+
// {}, // condition
|
|
230
|
+
// { complexAttributes: true }
|
|
231
|
+
// )
|
|
232
|
+
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* send message to OutFindDataComplete for searchResult service to know this requiredData is complete
|
|
237
|
+
* @param {string} fieldName
|
|
238
|
+
* @param {object} objType
|
|
239
|
+
* @param {object} identifiers
|
|
240
|
+
*
|
|
241
|
+
*/
|
|
242
|
+
module.exports.sendFindDataCompleteMessage = async (
|
|
243
|
+
_izContext,
|
|
244
|
+
fieldName,
|
|
245
|
+
objType,
|
|
246
|
+
identifiers,
|
|
247
|
+
requestProperties,
|
|
248
|
+
dataValue,
|
|
249
|
+
status,
|
|
250
|
+
callingFlow = "",
|
|
251
|
+
errorsFound = [],
|
|
252
|
+
timeCacheComplete = 0
|
|
253
|
+
) => {
|
|
254
|
+
|
|
255
|
+
//* validate status
|
|
256
|
+
if (status !== 'error' && status !== 'complete') {
|
|
257
|
+
throw new NoRetryError(`status: ${status} is not valided.`)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let msgParams = {
|
|
261
|
+
Message: JSON.stringify({
|
|
262
|
+
fieldName: fieldName,
|
|
263
|
+
objType: objType,
|
|
264
|
+
identifiers: identifiers,
|
|
265
|
+
requestProperties: requestProperties,
|
|
266
|
+
dataValue: dataValue,
|
|
267
|
+
status: status,
|
|
268
|
+
errorsFound: errorsFound,
|
|
269
|
+
timeCacheComplete: timeCacheComplete
|
|
270
|
+
}),
|
|
271
|
+
TopicArn: await snsSharedLib.snsTopicArn(_izContext, 'OutFindDataComplete')
|
|
272
|
+
};
|
|
273
|
+
if (callingFlow) {
|
|
274
|
+
msgParams.MessageAttributes = {
|
|
275
|
+
callingFlow: {
|
|
276
|
+
DataType: 'String',
|
|
277
|
+
StringValue: callingFlow
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
_izContext.logger.debug('msgParams before send to OutFindDataComplete topic...', msgParams);
|
|
282
|
+
await sns.publishAsync(_izContext, msgParams);
|
|
283
|
+
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
module.exports.createFindDataAwaitingStep = async (
|
|
289
|
+
_izContext,
|
|
290
|
+
awaitingId,
|
|
291
|
+
findDataId
|
|
292
|
+
) => {
|
|
293
|
+
//* insert into FindDataAwaitingStep
|
|
294
|
+
// call shared function
|
|
295
|
+
await asyncFlowSharedLib.createAwaitingStep(
|
|
296
|
+
_izContext,
|
|
297
|
+
awaitingId,
|
|
298
|
+
findDataId,
|
|
299
|
+
'FindDataAwaitingStep'
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Finds any FindDataAwaitingStep matching awaitingId
|
|
306
|
+
* @param {string} awaitingId
|
|
307
|
+
*
|
|
308
|
+
* @returns {string[]} array of resultIds
|
|
309
|
+
*/
|
|
310
|
+
module.exports.findFindDataIdsAwaitingStep = async (
|
|
311
|
+
_izContext,
|
|
312
|
+
awaitingId
|
|
313
|
+
) => {
|
|
314
|
+
try {
|
|
315
|
+
|
|
316
|
+
return await asyncFlowSharedLib.findPendingStepIdsAwaitingStep(
|
|
317
|
+
_izContext,
|
|
318
|
+
awaitingId,
|
|
319
|
+
'FindDataAwaitingStep'
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
} catch (err) {
|
|
323
|
+
_izContext.logger.error('error findFindDataAwaitingStep:', err)
|
|
324
|
+
throw (err)
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* deletes one FindDataAwaitingStep record
|
|
330
|
+
* @param {string} awaitingId
|
|
331
|
+
* @param {string} findDataId
|
|
332
|
+
*
|
|
333
|
+
* @returns {string[]} array of resultIds
|
|
334
|
+
*/
|
|
335
|
+
module.exports.removeFindDataAwaitingStep = async (
|
|
336
|
+
_izContext,
|
|
337
|
+
awaitingId,
|
|
338
|
+
findDataId
|
|
339
|
+
) => {
|
|
340
|
+
try {
|
|
341
|
+
|
|
342
|
+
// call shared fn
|
|
343
|
+
await asyncFlowSharedLib.removeAwaitingStep(
|
|
344
|
+
_izContext,
|
|
345
|
+
awaitingId,
|
|
346
|
+
findDataId,
|
|
347
|
+
'FindDataAwaitingStep'
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
} catch (err) {
|
|
351
|
+
_izContext.logger.error('error removeLogicalAwaitingStep:', err)
|
|
352
|
+
throw (err)
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
module.exports.createFindDataSortedRequest = async (
|
|
358
|
+
_izContext,
|
|
359
|
+
sortResultId,
|
|
360
|
+
findDataId,
|
|
361
|
+
aggregation,
|
|
362
|
+
excludeEmpty,
|
|
363
|
+
prefix = ""
|
|
364
|
+
) => {
|
|
365
|
+
|
|
366
|
+
// NOTE (Tam 14 Dec 2021): new idea to standardized table, put to same FindDataAwaitingStep, shared table and function.
|
|
367
|
+
await asyncFlowSharedLib.createAwaitingStep(
|
|
368
|
+
_izContext,
|
|
369
|
+
asyncFlowSharedLib.createAwaitingStepId(sortResultId, prefix),
|
|
370
|
+
findDataId, // pendingStepId
|
|
371
|
+
'FindDataAwaitingStep',
|
|
372
|
+
{ //additionalAttributes
|
|
373
|
+
aggregation: aggregation,
|
|
374
|
+
excludeEmpty: excludeEmpty
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
module.exports.findFindDataSortedRequests = async (
|
|
381
|
+
_izContext,
|
|
382
|
+
sortResultId,
|
|
383
|
+
prefix = ""
|
|
384
|
+
) => {
|
|
385
|
+
try {
|
|
386
|
+
|
|
387
|
+
return await asyncFlowSharedLib.findPendingStepIdsAwaitingStep(
|
|
388
|
+
_izContext,
|
|
389
|
+
asyncFlowSharedLib.createAwaitingStepId(sortResultId, prefix),
|
|
390
|
+
'FindDataAwaitingStep'
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
} catch (err) {
|
|
395
|
+
_izContext.logger.error('ERROR findFindDataSortedRequests:', err)
|
|
396
|
+
throw (err)
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* deletes one FindDataSortedRequest record
|
|
402
|
+
* @param {string} findDataId
|
|
403
|
+
*
|
|
404
|
+
* @returns {string[]} array of resultIds
|
|
405
|
+
*/
|
|
406
|
+
module.exports.removeFindDataSortedRequest = async (
|
|
407
|
+
_izContext,
|
|
408
|
+
sortResultId,
|
|
409
|
+
findDataId,
|
|
410
|
+
prefix = ""
|
|
411
|
+
) => {
|
|
412
|
+
try {
|
|
413
|
+
|
|
414
|
+
await asyncFlowSharedLib.removeAwaitingStep(
|
|
415
|
+
_izContext,
|
|
416
|
+
asyncFlowSharedLib.createAwaitingStepId(sortResultId, prefix),
|
|
417
|
+
findDataId, //pendingStepId
|
|
418
|
+
'FindDataAwaitingStep'
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
} catch (err) {
|
|
422
|
+
_izContext.logger.debug('ERROR removeFindDataSortedRequest:', err)
|
|
423
|
+
throw (err)
|
|
424
|
+
}
|
|
425
|
+
};
|