@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 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.1",
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
- "@izara_project/izara-core-library-service-schemas": "^1.0.38",
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
+ };