@cumulus/es-client 13.4.0 → 14.0.0
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/README.md +7 -0
- package/esDefaults.js +1 -1
- package/indexer.js +70 -16
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -8,6 +8,13 @@ Utilities for working with Elasticsearch.
|
|
|
8
8
|
npm install @cumulus/es-client
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## Notes
|
|
12
|
+
|
|
13
|
+
### Sorting
|
|
14
|
+
|
|
15
|
+
It is possible to sort the Elastic Search results by specifying `sort_by`, `sort_key`, and `order` params.
|
|
16
|
+
If not provided, the default sorting will be applied (`{ timestamp: { order: 'desc' } }` as of this writing).
|
|
17
|
+
|
|
11
18
|
## About Cumulus
|
|
12
19
|
|
|
13
20
|
Cumulus is a cloud-based data ingest, archive, distribution and management prototype for NASA's
|
package/esDefaults.js
CHANGED
package/indexer.js
CHANGED
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
13
|
const cloneDeep = require('lodash/cloneDeep');
|
|
14
|
+
const isEqual = require('lodash/isEqual');
|
|
14
15
|
|
|
15
16
|
const Logger = require('@cumulus/logger');
|
|
16
17
|
const { inTestMode } = require('@cumulus/common/test-utils');
|
|
17
|
-
const { IndexExistsError } = require('@cumulus/errors');
|
|
18
|
+
const { IndexExistsError, ValidationError } = require('@cumulus/errors');
|
|
18
19
|
const { constructCollectionId } = require('@cumulus/message/Collections');
|
|
20
|
+
const { removeNilProperties } = require('@cumulus/common/util');
|
|
19
21
|
|
|
20
22
|
const { Search, defaultIndexAlias } = require('./search');
|
|
21
23
|
const mappings = require('./config/mappings.json');
|
|
@@ -284,15 +286,26 @@ async function indexGranule(esClient, payload, index = defaultIndexAlias, type =
|
|
|
284
286
|
);
|
|
285
287
|
}
|
|
286
288
|
|
|
289
|
+
const granuleInvalidNullFields = [
|
|
290
|
+
'granuleId',
|
|
291
|
+
'collectionId',
|
|
292
|
+
'status',
|
|
293
|
+
'updatedAt',
|
|
294
|
+
'execution',
|
|
295
|
+
'createdAt',
|
|
296
|
+
];
|
|
297
|
+
|
|
287
298
|
/**
|
|
288
299
|
* Upserts a granule in Elasticsearch
|
|
289
300
|
*
|
|
290
301
|
* @param {Object} params
|
|
291
|
-
* @param {Object} params.esClient
|
|
292
|
-
* @param {Object} params.updates
|
|
293
|
-
* @param {string} params.index
|
|
294
|
-
* @param {string} params.type
|
|
295
|
-
* @param {string} [params.refresh]
|
|
302
|
+
* @param {Object} params.esClient - Elasticsearch Connection object
|
|
303
|
+
* @param {Object} params.updates - Updates to make
|
|
304
|
+
* @param {string} params.index - Elasticsearch index alias (default defined in search.js)
|
|
305
|
+
* @param {string} params.type - Elasticsearch type (default: granule)
|
|
306
|
+
* @param {string} [params.refresh] - whether to refresh the index on update or not
|
|
307
|
+
* @param {boolean} writeConstraints - boolean toggle restricting if conditionals should
|
|
308
|
+
* be used to determine write eligibility
|
|
296
309
|
* @returns {Promise} Elasticsearch response
|
|
297
310
|
*/
|
|
298
311
|
async function upsertGranule({
|
|
@@ -301,7 +314,12 @@ async function upsertGranule({
|
|
|
301
314
|
index = defaultIndexAlias,
|
|
302
315
|
type = 'granule',
|
|
303
316
|
refresh,
|
|
304
|
-
}) {
|
|
317
|
+
}, writeConstraints = true) {
|
|
318
|
+
Object.keys(updates).forEach((key) => {
|
|
319
|
+
if (updates[key] === null && granuleInvalidNullFields.includes(key)) {
|
|
320
|
+
throw new ValidationError(`Attempted DynamoDb write with invalid key ${key} set to null. Please remove or change this field and retry`);
|
|
321
|
+
}
|
|
322
|
+
});
|
|
305
323
|
// If the granule exists in 'deletedgranule', delete it first before inserting the granule
|
|
306
324
|
// into ES. Ignore 404 error, so the deletion still succeeds if the record doesn't exist.
|
|
307
325
|
const delGranParams = {
|
|
@@ -313,7 +331,49 @@ async function upsertGranule({
|
|
|
313
331
|
};
|
|
314
332
|
await esClient.delete(delGranParams, { ignore: [404] });
|
|
315
333
|
|
|
316
|
-
|
|
334
|
+
// Remove nils in case there isn't a collision
|
|
335
|
+
const upsertDoc = removeNilProperties(updates);
|
|
336
|
+
let removeString = '';
|
|
337
|
+
|
|
338
|
+
// Set field removal for null values
|
|
339
|
+
Object.entries(updates).forEach(([fieldName, value]) => {
|
|
340
|
+
// File removal is a special case as null gets set to []
|
|
341
|
+
if (fieldName === 'files' && isEqual(value, [])) {
|
|
342
|
+
removeString += `ctx._source.remove('${fieldName}'); `;
|
|
343
|
+
}
|
|
344
|
+
if (value === null) {
|
|
345
|
+
removeString += `ctx._source.remove('${fieldName}'); `;
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
let inlineDocWriteString = 'ctx._source.putAll(params.doc);';
|
|
350
|
+
if (removeString !== '') {
|
|
351
|
+
inlineDocWriteString += removeString;
|
|
352
|
+
}
|
|
353
|
+
let inline = inlineDocWriteString;
|
|
354
|
+
|
|
355
|
+
if (writeConstraints === true) {
|
|
356
|
+
// Because both API write and message write chains use the granule model to store records, in
|
|
357
|
+
// cases where createdAt does not exist on the granule, we assume overwrite protections are
|
|
358
|
+
// undesired behavior via business logic on the message write logic
|
|
359
|
+
inline = `
|
|
360
|
+
if ((ctx._source.createdAt === null || params.doc.createdAt >= ctx._source.createdAt)
|
|
361
|
+
&& (params.doc.status != 'running' || (params.doc.status == 'running' && params.doc.execution != ctx._source.execution))) {
|
|
362
|
+
${inlineDocWriteString}
|
|
363
|
+
} else {
|
|
364
|
+
ctx.op = 'none';
|
|
365
|
+
}
|
|
366
|
+
`;
|
|
367
|
+
if (!updates.createdAt) {
|
|
368
|
+
inline = `
|
|
369
|
+
if (params.doc.status != 'running' || (params.doc.status == 'running' && params.doc.execution != ctx._source.execution)) {
|
|
370
|
+
${inlineDocWriteString}
|
|
371
|
+
} else {
|
|
372
|
+
ctx.op = 'none';
|
|
373
|
+
}
|
|
374
|
+
`;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
317
377
|
|
|
318
378
|
return await esClient.update({
|
|
319
379
|
index,
|
|
@@ -323,14 +383,7 @@ async function upsertGranule({
|
|
|
323
383
|
body: {
|
|
324
384
|
script: {
|
|
325
385
|
lang: 'painless',
|
|
326
|
-
inline
|
|
327
|
-
if ((ctx._source.createdAt === null || params.doc.createdAt >= ctx._source.createdAt)
|
|
328
|
-
&& (params.doc.status != 'running' || (params.doc.status == 'running' && params.doc.execution != ctx._source.execution))) {
|
|
329
|
-
ctx._source.putAll(params.doc);
|
|
330
|
-
} else {
|
|
331
|
-
ctx.op = 'none';
|
|
332
|
-
}
|
|
333
|
-
`,
|
|
386
|
+
inline,
|
|
334
387
|
params: {
|
|
335
388
|
doc: upsertDoc,
|
|
336
389
|
},
|
|
@@ -709,4 +762,5 @@ module.exports = {
|
|
|
709
762
|
deleteGranule,
|
|
710
763
|
deleteExecution,
|
|
711
764
|
deleteReconciliationReport,
|
|
765
|
+
granuleInvalidNullFields,
|
|
712
766
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cumulus/es-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.0.0",
|
|
4
4
|
"description": "Utilities for working with Elasticsearch",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"CUMULUS",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"author": "Cumulus Authors",
|
|
31
31
|
"license": "Apache-2.0",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@cumulus/common": "
|
|
34
|
-
"@cumulus/errors": "
|
|
35
|
-
"@cumulus/logger": "
|
|
36
|
-
"@cumulus/message": "
|
|
33
|
+
"@cumulus/common": "14.0.0",
|
|
34
|
+
"@cumulus/errors": "14.0.0",
|
|
35
|
+
"@cumulus/logger": "14.0.0",
|
|
36
|
+
"@cumulus/message": "14.0.0",
|
|
37
37
|
"@elastic/elasticsearch": "^5.6.20",
|
|
38
38
|
"aws-elasticsearch-connector": "8.2.0",
|
|
39
39
|
"aws-sdk": "^2.585.0",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"p-limit": "^1.2.0"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@cumulus/aws-client": "
|
|
46
|
-
"@cumulus/test-data": "
|
|
45
|
+
"@cumulus/aws-client": "14.0.0",
|
|
46
|
+
"@cumulus/test-data": "14.0.0",
|
|
47
47
|
"p-each-series": "^2.1.0"
|
|
48
48
|
},
|
|
49
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "bc0cd0857e007b64e4e8809f7de16a4aeb1e6840"
|
|
50
50
|
}
|