@cumulus/db 19.1.0 → 19.2.0-alpha.1

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.
Files changed (53) hide show
  1. package/dist/index.d.ts +11 -4
  2. package/dist/index.js +21 -6
  3. package/dist/lib/QuerySearchClient.d.ts +0 -2
  4. package/dist/lib/QuerySearchClient.js +0 -2
  5. package/dist/lib/collection.d.ts +8 -0
  6. package/dist/lib/collection.js +36 -1
  7. package/dist/lib/execution.d.ts +14 -12
  8. package/dist/lib/execution.js +23 -27
  9. package/dist/lib/granule.d.ts +13 -17
  10. package/dist/lib/granule.js +22 -24
  11. package/dist/migrations/20240814185217_create_reconciliation_reports_table.d.ts +4 -0
  12. package/dist/migrations/20240814185217_create_reconciliation_reports_table.js +40 -0
  13. package/dist/models/file.d.ts +4 -0
  14. package/dist/models/file.js +8 -0
  15. package/dist/models/reconciliation_report.d.ts +10 -0
  16. package/dist/models/reconciliation_report.js +25 -0
  17. package/dist/search/AsyncOperationSearch.d.ts +32 -0
  18. package/dist/search/AsyncOperationSearch.js +55 -0
  19. package/dist/search/BaseSearch.d.ts +8 -2
  20. package/dist/search/BaseSearch.js +40 -13
  21. package/dist/search/CollectionSearch.d.ts +14 -21
  22. package/dist/search/CollectionSearch.js +50 -52
  23. package/dist/search/ExecutionSearch.d.ts +4 -4
  24. package/dist/search/ExecutionSearch.js +7 -8
  25. package/dist/search/GranuleSearch.d.ts +14 -6
  26. package/dist/search/GranuleSearch.js +56 -5
  27. package/dist/search/PdrSearch.d.ts +50 -0
  28. package/dist/search/PdrSearch.js +100 -0
  29. package/dist/search/ProviderSearch.d.ts +32 -0
  30. package/dist/search/ProviderSearch.js +57 -0
  31. package/dist/search/ReconciliationReportSearch.d.ts +42 -0
  32. package/dist/search/ReconciliationReportSearch.js +72 -0
  33. package/dist/search/RuleSearch.d.ts +49 -0
  34. package/dist/search/RuleSearch.js +95 -0
  35. package/dist/search/StatsSearch.d.ts +0 -1
  36. package/dist/search/StatsSearch.js +3 -3
  37. package/dist/search/field-mapping.js +105 -1
  38. package/dist/search/queries.js +4 -2
  39. package/dist/tables.d.ts +1 -0
  40. package/dist/tables.js +1 -0
  41. package/dist/test-utils.d.ts +3 -17
  42. package/dist/test-utils.js +10 -1
  43. package/dist/translate/async_operations.js +2 -1
  44. package/dist/translate/pdr.d.ts +19 -0
  45. package/dist/translate/pdr.js +36 -19
  46. package/dist/translate/reconciliation_reports.d.ts +17 -0
  47. package/dist/translate/reconciliation_reports.js +36 -0
  48. package/dist/translate/rules.d.ts +3 -0
  49. package/dist/translate/rules.js +16 -12
  50. package/dist/types/reconciliation_report.d.ts +29 -0
  51. package/dist/types/reconciliation_report.js +3 -0
  52. package/dist/types/search.d.ts +3 -2
  53. package/package.json +8 -8
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AsyncOperationSearch = void 0;
7
+ const pick_1 = __importDefault(require("lodash/pick"));
8
+ const logger_1 = __importDefault(require("@cumulus/logger"));
9
+ const BaseSearch_1 = require("./BaseSearch");
10
+ const async_operations_1 = require("../translate/async_operations");
11
+ const log = new logger_1.default({ sender: '@cumulus/db/AsyncOperationSearch' });
12
+ /**
13
+ * Class to build and execute db search query for asyncOperation
14
+ */
15
+ class AsyncOperationSearch extends BaseSearch_1.BaseSearch {
16
+ constructor(event) {
17
+ super(event, 'asyncOperation');
18
+ }
19
+ /**
20
+ * Build queries for infix and prefix
21
+ *
22
+ * @param params
23
+ * @param params.countQuery - query builder for getting count
24
+ * @param params.searchQuery - query builder for search
25
+ * @param [params.dbQueryParameters] - db query parameters
26
+ */
27
+ buildInfixPrefixQuery(params) {
28
+ const { countQuery, searchQuery, dbQueryParameters } = params;
29
+ const { infix, prefix } = dbQueryParameters ?? this.dbQueryParameters;
30
+ if (infix) {
31
+ [countQuery, searchQuery].forEach((query) => query.whereRaw(`${this.tableName}.id::text like ?`, `%${infix}%`));
32
+ }
33
+ if (prefix) {
34
+ [countQuery, searchQuery].forEach((query) => query.whereRaw(`${this.tableName}.id::text like ?`, `${prefix}%`));
35
+ }
36
+ }
37
+ /**
38
+ * Translate postgres records to api records
39
+ *
40
+ * @param pgRecords - postgres records returned from query
41
+ * @returns translated api records
42
+ */
43
+ translatePostgresRecordsToApiRecords(pgRecords) {
44
+ log.debug(`translatePostgresRecordsToApiRecords number of records ${pgRecords.length} `);
45
+ const { fields } = this.dbQueryParameters;
46
+ const apiRecords = pgRecords.map((item) => {
47
+ const pgAsyncOperation = item;
48
+ const apiRecord = (0, async_operations_1.translatePostgresAsyncOperationToApiAsyncOperation)(pgAsyncOperation);
49
+ return fields ? (0, pick_1.default)(apiRecord, fields) : apiRecord;
50
+ });
51
+ return apiRecords;
52
+ }
53
+ }
54
+ exports.AsyncOperationSearch = AsyncOperationSearch;
55
+ //# sourceMappingURL=AsyncOperationSearch.js.map
@@ -7,7 +7,7 @@ export declare const typeToTable: {
7
7
  /**
8
8
  * Class to build and execute db search query
9
9
  */
10
- declare class BaseSearch {
10
+ declare abstract class BaseSearch {
11
11
  readonly type: string;
12
12
  readonly tableName: string;
13
13
  readonly queryStringParameters: QueryStringParameters;
@@ -19,6 +19,12 @@ declare class BaseSearch {
19
19
  * @returns whether collection search is needed
20
20
  */
21
21
  protected searchCollection(): boolean;
22
+ /**
23
+ * check if joined executions table search is needed
24
+ *
25
+ * @returns whether execution search is needed
26
+ */
27
+ protected searchExecution(): boolean;
22
28
  /**
23
29
  * check if joined pdrs table search is needed
24
30
  *
@@ -58,7 +64,7 @@ declare class BaseSearch {
58
64
  * Build basic query
59
65
  *
60
66
  * @param knex - DB client
61
- * @throws - function is not implemented
67
+ * @returns queries for getting count and search result
62
68
  */
63
69
  protected buildBasicQuery(knex: Knex): {
64
70
  countQuery?: Knex.QueryBuilder;
@@ -19,6 +19,7 @@ exports.typeToTable = {
19
19
  pdr: tables_1.TableNames.pdrs,
20
20
  provider: tables_1.TableNames.providers,
21
21
  rule: tables_1.TableNames.rules,
22
+ reconciliationReport: tables_1.TableNames.reconciliationReports,
22
23
  };
23
24
  /**
24
25
  * Class to build and execute db search query
@@ -46,6 +47,15 @@ class BaseSearch {
46
47
  || terms?.collectionName
47
48
  || terms?.collectionVersion);
48
49
  }
50
+ /**
51
+ * check if joined executions table search is needed
52
+ *
53
+ * @returns whether execution search is needed
54
+ */
55
+ searchExecution() {
56
+ const { not, term, terms } = this.dbQueryParameters;
57
+ return !!(not?.executionArn || term?.executionArn || terms?.executionArn);
58
+ }
49
59
  /**
50
60
  * check if joined pdrs table search is needed
51
61
  *
@@ -113,11 +123,14 @@ class BaseSearch {
113
123
  * Build basic query
114
124
  *
115
125
  * @param knex - DB client
116
- * @throws - function is not implemented
126
+ * @returns queries for getting count and search result
117
127
  */
118
128
  buildBasicQuery(knex) {
119
- log.debug(`buildBasicQuery is not implemented ${knex.constructor.name}`);
120
- throw new Error('buildBasicQuery is not implemented');
129
+ const countQuery = knex(this.tableName)
130
+ .count('*');
131
+ const searchQuery = knex(this.tableName)
132
+ .select(`${this.tableName}.*`);
133
+ return { countQuery, searchQuery };
121
134
  }
122
135
  /**
123
136
  * Build queries for infix and prefix
@@ -150,6 +163,9 @@ class BaseSearch {
150
163
  case 'collectionVersion':
151
164
  [countQuery, searchQuery].forEach((query) => query?.[queryMethod](`${this.tableName}.collection_cumulus_id`));
152
165
  break;
166
+ case 'executionArn':
167
+ [countQuery, searchQuery].forEach((query) => query?.[queryMethod](`${this.tableName}.execution_cumulus_id`));
168
+ break;
153
169
  case 'providerName':
154
170
  [countQuery, searchQuery].forEach((query) => query?.[queryMethod](`${this.tableName}.provider_cumulus_id`));
155
171
  break;
@@ -185,13 +201,12 @@ class BaseSearch {
185
201
  const { countQuery, searchQuery, dbQueryParameters } = params;
186
202
  const { range = {} } = dbQueryParameters ?? this.dbQueryParameters;
187
203
  Object.entries(range).forEach(([name, rangeValues]) => {
188
- if (rangeValues.gte) {
189
- countQuery?.where(`${this.tableName}.${name}`, '>=', rangeValues.gte);
190
- searchQuery.where(`${this.tableName}.${name}`, '>=', rangeValues.gte);
204
+ const { gte, lte } = rangeValues;
205
+ if (gte) {
206
+ [countQuery, searchQuery].forEach((query) => query?.where(`${this.tableName}.${name}`, '>=', gte));
191
207
  }
192
- if (rangeValues.lte) {
193
- countQuery?.where(`${this.tableName}.${name}`, '<=', rangeValues.lte);
194
- searchQuery.where(`${this.tableName}.${name}`, '<=', rangeValues.lte);
208
+ if (lte) {
209
+ [countQuery, searchQuery].forEach((query) => query?.where(`${this.tableName}.${name}`, '<=', lte));
195
210
  }
196
211
  });
197
212
  }
@@ -215,6 +230,9 @@ class BaseSearch {
215
230
  case 'collectionVersion':
216
231
  [countQuery, searchQuery].forEach((query) => query?.where(`${collectionsTable}.version`, value));
217
232
  break;
233
+ case 'executionArn':
234
+ [countQuery, searchQuery].forEach((query) => query?.where(`${executionsTable}.arn`, value));
235
+ break;
218
236
  case 'providerName':
219
237
  [countQuery, searchQuery].forEach((query) => query?.where(`${providersTable}.name`, value));
220
238
  break;
@@ -223,7 +241,7 @@ class BaseSearch {
223
241
  break;
224
242
  case 'error.Error':
225
243
  [countQuery, searchQuery]
226
- .forEach((query) => query?.whereRaw(`${this.tableName}.error->>'Error' = '${value}'`));
244
+ .forEach((query) => value && query?.whereRaw(`${this.tableName}.error->>'Error' = ?`, value));
227
245
  break;
228
246
  case 'asyncOperationId':
229
247
  [countQuery, searchQuery].forEach((query) => query?.where(`${asyncOperationsTable}.id`, value));
@@ -265,6 +283,9 @@ class BaseSearch {
265
283
  }
266
284
  Object.entries((0, omit_1.default)(terms, ['collectionName', 'collectionVersion'])).forEach(([name, value]) => {
267
285
  switch (name) {
286
+ case 'executionArn':
287
+ [countQuery, searchQuery].forEach((query) => query?.whereIn(`${executionsTable}.arn`, value));
288
+ break;
268
289
  case 'providerName':
269
290
  [countQuery, searchQuery].forEach((query) => query?.whereIn(`${providersTable}.name`, value));
270
291
  break;
@@ -273,7 +294,7 @@ class BaseSearch {
273
294
  break;
274
295
  case 'error.Error':
275
296
  [countQuery, searchQuery]
276
- .forEach((query) => query?.whereRaw(`${this.tableName}.error->>'Error' in ('${value.join('\',\'')}')`));
297
+ .forEach((query) => query?.whereRaw(`${this.tableName}.error->>'Error' in (${value.map(() => '?').join(',')})`, [...value]));
277
298
  break;
278
299
  case 'asyncOperationId':
279
300
  [countQuery, searchQuery].forEach((query) => query?.whereIn(`${asyncOperationsTable}.id`, value));
@@ -308,6 +329,9 @@ class BaseSearch {
308
329
  }
309
330
  Object.entries((0, omit_1.default)(term, ['collectionName', 'collectionVersion'])).forEach(([name, value]) => {
310
331
  switch (name) {
332
+ case 'executionArn':
333
+ [countQuery, searchQuery].forEach((query) => query?.whereNot(`${executionsTable}.arn`, value));
334
+ break;
311
335
  case 'providerName':
312
336
  [countQuery, searchQuery].forEach((query) => query?.whereNot(`${providersTable}.name`, value));
313
337
  break;
@@ -321,7 +345,7 @@ class BaseSearch {
321
345
  [countQuery, searchQuery].forEach((query) => query?.whereNot(`${executionsTable}_parent.arn`, value));
322
346
  break;
323
347
  case 'error.Error':
324
- [countQuery, searchQuery].forEach((query) => query?.whereRaw(`${this.tableName}.error->>'Error' != '${value}'`));
348
+ [countQuery, searchQuery].forEach((query) => value && query?.whereRaw(`${this.tableName}.error->>'Error' != ?`, value));
325
349
  break;
326
350
  default:
327
351
  [countQuery, searchQuery].forEach((query) => query?.whereNot(`${this.tableName}.${name}`, value));
@@ -343,6 +367,9 @@ class BaseSearch {
343
367
  if (key.column.startsWith('error')) {
344
368
  searchQuery.orderByRaw(`${this.tableName}.error ->> 'Error' ${key.order}`);
345
369
  }
370
+ else if (dbQueryParameters?.collate) {
371
+ searchQuery.orderByRaw(`${key} collate \"${dbQueryParameters.collate}\"`);
372
+ }
346
373
  else {
347
374
  searchQuery.orderBy([key]);
348
375
  }
@@ -369,7 +396,7 @@ class BaseSearch {
369
396
  */
370
397
  async getEstimatedRowcount(params) {
371
398
  const { knex, tableName = this.tableName } = params;
372
- const query = knex.raw(`EXPLAIN (FORMAT JSON) select * from "${tableName}"`);
399
+ const query = knex.raw('EXPLAIN (FORMAT JSON) select * from ??', tableName);
373
400
  log.debug(`Estimating the row count ${query.toSQL().sql}`);
374
401
  const countResult = await query;
375
402
  const countPath = 'rows[0]["QUERY PLAN"][0].Plan["Plan Rows"]';
@@ -20,16 +20,6 @@ export declare class CollectionSearch extends BaseSearch {
20
20
  readonly active: boolean;
21
21
  readonly includeStats: boolean;
22
22
  constructor(event: QueryEvent);
23
- /**
24
- * Build basic query
25
- *
26
- * @param knex - DB client
27
- * @returns queries for getting count and search result
28
- */
29
- protected buildBasicQuery(knex: Knex): {
30
- countQuery: Knex.QueryBuilder;
31
- searchQuery: Knex.QueryBuilder;
32
- };
33
23
  /**
34
24
  * Build queries for infix and prefix
35
25
  *
@@ -44,20 +34,23 @@ export declare class CollectionSearch extends BaseSearch {
44
34
  dbQueryParameters?: DbQueryParameters;
45
35
  }): void;
46
36
  /**
47
- * Build queries for range fields
37
+ * Build subquery for active collections
38
+ * The subquery will search granules
48
39
  *
49
- * @param params
50
- * @param params.knex - db client
51
- * @param [params.countQuery] - query builder for getting count
52
- * @param params.searchQuery - query builder for search
53
- * @param [params.dbQueryParameters] - db query parameters
40
+ * @param knex - db client
41
+ * @returns granule query
54
42
  */
55
- protected buildRangeQuery(params: {
56
- knex: Knex;
57
- countQuery: Knex.QueryBuilder;
43
+ private buildSubQueryForActiveCollections;
44
+ /**
45
+ * Build the search query
46
+ *
47
+ * @param knex - DB client
48
+ * @returns queries for getting count and search result
49
+ */
50
+ protected buildSearch(knex: Knex): {
51
+ countQuery?: Knex.QueryBuilder;
58
52
  searchQuery: Knex.QueryBuilder;
59
- dbQueryParameters?: DbQueryParameters;
60
- }): void;
53
+ };
61
54
  /**
62
55
  * Executes stats query to get granules' status aggregation
63
56
  *
@@ -4,12 +4,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.CollectionSearch = void 0;
7
+ const omitBy_1 = __importDefault(require("lodash/omitBy"));
7
8
  const pick_1 = __importDefault(require("lodash/pick"));
8
9
  const logger_1 = __importDefault(require("@cumulus/logger"));
9
10
  const BaseSearch_1 = require("./BaseSearch");
11
+ const queries_1 = require("./queries");
12
+ const GranuleSearch_1 = require("./GranuleSearch");
10
13
  const collections_1 = require("../translate/collections");
11
14
  const tables_1 = require("../tables");
12
15
  const log = new logger_1.default({ sender: '@cumulus/db/CollectionSearch' });
16
+ const granuleFields = ['createdAt', 'granuleId', 'timestamp', 'updatedAt'];
17
+ const isGranuleField = (_value, key) => granuleFields.includes(key.split('__')[0]);
13
18
  /**
14
19
  * Class to build and execute db search query for collections
15
20
  */
@@ -19,19 +24,10 @@ class CollectionSearch extends BaseSearch_1.BaseSearch {
19
24
  super({ queryStringParameters }, 'collection');
20
25
  this.active = (active === 'true');
21
26
  this.includeStats = (includeStats === 'true');
22
- }
23
- /**
24
- * Build basic query
25
- *
26
- * @param knex - DB client
27
- * @returns queries for getting count and search result
28
- */
29
- buildBasicQuery(knex) {
30
- const countQuery = knex(this.tableName)
31
- .count('*');
32
- const searchQuery = knex(this.tableName)
33
- .select(`${this.tableName}.*`);
34
- return { countQuery, searchQuery };
27
+ // for active collection search, omit the fields which are for searching granules
28
+ if (this.active) {
29
+ this.dbQueryParameters = (0, queries_1.convertQueryStringToDbQueryParameters)(this.type, (0, omitBy_1.default)(this.queryStringParameters, isGranuleField));
30
+ }
35
31
  }
36
32
  /**
37
33
  * Build queries for infix and prefix
@@ -48,38 +44,43 @@ class CollectionSearch extends BaseSearch_1.BaseSearch {
48
44
  [countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.name`, `%${infix}%`));
49
45
  }
50
46
  if (prefix) {
51
- [countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.name`, `%${prefix}%`));
47
+ [countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.name`, `${prefix}%`));
52
48
  }
53
49
  }
54
50
  /**
55
- * Build queries for range fields
51
+ * Build subquery for active collections
52
+ * The subquery will search granules
56
53
  *
57
- * @param params
58
- * @param params.knex - db client
59
- * @param [params.countQuery] - query builder for getting count
60
- * @param params.searchQuery - query builder for search
61
- * @param [params.dbQueryParameters] - db query parameters
54
+ * @param knex - db client
55
+ * @returns granule query
56
+ */
57
+ buildSubQueryForActiveCollections(knex) {
58
+ const granulesTable = tables_1.TableNames.granules;
59
+ const granuleSearch = new GranuleSearch_1.GranuleSearch({ queryStringParameters: this.queryStringParameters });
60
+ const { countQuery: subQuery } = granuleSearch.buildSearchForActiveCollections(knex);
61
+ subQuery
62
+ .clear('select')
63
+ .select(1)
64
+ .where(`${granulesTable}.collection_cumulus_id`, knex.raw(`${this.tableName}.cumulus_id`))
65
+ .limit(1);
66
+ return subQuery;
67
+ }
68
+ /**
69
+ * Build the search query
70
+ *
71
+ * @param knex - DB client
72
+ * @returns queries for getting count and search result
62
73
  */
63
- buildRangeQuery(params) {
74
+ buildSearch(knex) {
75
+ const queries = super.buildSearch(knex);
64
76
  if (!this.active) {
65
- super.buildRangeQuery(params);
66
- return;
77
+ return queries;
67
78
  }
68
- const granulesTable = tables_1.TableNames.granules;
69
- const { knex, countQuery, searchQuery, dbQueryParameters } = params;
70
- const { range = {} } = dbQueryParameters ?? this.dbQueryParameters;
71
- const subQuery = knex.select(1).from(granulesTable)
72
- .where(`${granulesTable}.collection_cumulus_id`, knex.raw(`${this.tableName}.cumulus_id`));
73
- Object.entries(range).forEach(([name, rangeValues]) => {
74
- if (rangeValues.gte) {
75
- subQuery.where(`${granulesTable}.${name}`, '>=', rangeValues.gte);
76
- }
77
- if (rangeValues.lte) {
78
- subQuery.where(`${granulesTable}.${name}`, '<=', rangeValues.lte);
79
- }
80
- });
81
- subQuery.limit(1);
82
- [countQuery, searchQuery].forEach((query) => query.whereExists(subQuery));
79
+ const subQuery = this.buildSubQueryForActiveCollections(knex);
80
+ const { countQuery, searchQuery } = queries;
81
+ [countQuery, searchQuery].forEach((query) => query?.whereExists(subQuery));
82
+ log.debug(`buildSearch returns countQuery: ${countQuery?.toSQL().sql}, searchQuery: ${searchQuery.toSQL().sql}`);
83
+ return { countQuery, searchQuery };
83
84
  }
84
85
  /**
85
86
  * Executes stats query to get granules' status aggregation
@@ -90,21 +91,19 @@ class CollectionSearch extends BaseSearch_1.BaseSearch {
90
91
  */
91
92
  async retrieveGranuleStats(collectionCumulusIds, knex) {
92
93
  const granulesTable = tables_1.TableNames.granules;
93
- const statsQuery = knex(granulesTable)
94
+ let statsQuery = knex(granulesTable);
95
+ if (this.active) {
96
+ const granuleSearch = new GranuleSearch_1.GranuleSearch({
97
+ queryStringParameters: this.queryStringParameters,
98
+ });
99
+ const { countQuery } = granuleSearch.buildSearchForActiveCollections(knex);
100
+ statsQuery = countQuery.clear('select');
101
+ }
102
+ statsQuery
94
103
  .select(`${granulesTable}.collection_cumulus_id`, `${granulesTable}.status`)
95
104
  .count('*')
96
105
  .groupBy(`${granulesTable}.collection_cumulus_id`, `${granulesTable}.status`)
97
106
  .whereIn(`${granulesTable}.collection_cumulus_id`, collectionCumulusIds);
98
- if (this.active) {
99
- Object.entries(this.dbQueryParameters?.range ?? {}).forEach(([name, rangeValues]) => {
100
- if (rangeValues.gte) {
101
- statsQuery.where(`${granulesTable}.${name}`, '>=', rangeValues.gte);
102
- }
103
- if (rangeValues.lte) {
104
- statsQuery.where(`${granulesTable}.${name}`, '<=', rangeValues.lte);
105
- }
106
- });
107
- }
108
107
  log.debug(`retrieveGranuleStats statsQuery: ${statsQuery?.toSQL().sql}`);
109
108
  const results = await statsQuery;
110
109
  const reduced = results.reduce((acc, record) => {
@@ -133,6 +132,7 @@ class CollectionSearch extends BaseSearch_1.BaseSearch {
133
132
  */
134
133
  async translatePostgresRecordsToApiRecords(pgRecords, knex) {
135
134
  log.debug(`translatePostgresRecordsToApiRecords number of records ${pgRecords.length} `);
135
+ const { fields } = this.dbQueryParameters;
136
136
  let statsRecords;
137
137
  const cumulusIds = pgRecords.map((record) => record.cumulus_id);
138
138
  if (this.includeStats) {
@@ -140,9 +140,7 @@ class CollectionSearch extends BaseSearch_1.BaseSearch {
140
140
  }
141
141
  const apiRecords = pgRecords.map((record) => {
142
142
  const apiRecord = (0, collections_1.translatePostgresCollectionToApiCollection)(record);
143
- const apiRecordFinal = this.dbQueryParameters.fields
144
- ? (0, pick_1.default)(apiRecord, this.dbQueryParameters.fields)
145
- : apiRecord;
143
+ const apiRecordFinal = fields ? (0, pick_1.default)(apiRecord, fields) : apiRecord;
146
144
  if (statsRecords) {
147
145
  apiRecordFinal.stats = statsRecords[record.cumulus_id] ? statsRecords[record.cumulus_id]
148
146
  : {
@@ -16,15 +16,15 @@ interface ExecutionRecord extends BaseRecord, PostgresExecutionRecord {
16
16
  export declare class ExecutionSearch extends BaseSearch {
17
17
  constructor(event: QueryEvent);
18
18
  /**
19
- * check if joined async_ops table search is needed
19
+ * check if joined async_operations table search is needed
20
20
  *
21
- * @returns whether collection search is needed
21
+ * @returns whether async_operations search is needed
22
22
  */
23
23
  protected searchAsync(): boolean;
24
24
  /**
25
- * check if joined async_ops table search is needed
25
+ * check if joined parent execution table search is needed
26
26
  *
27
- * @returns whether collection search is needed
27
+ * @returns whether parent execution search is needed
28
28
  */
29
29
  protected searchParent(): boolean;
30
30
  /**
@@ -24,18 +24,18 @@ class ExecutionSearch extends BaseSearch_1.BaseSearch {
24
24
  super(event, 'execution');
25
25
  }
26
26
  /**
27
- * check if joined async_ops table search is needed
27
+ * check if joined async_operations table search is needed
28
28
  *
29
- * @returns whether collection search is needed
29
+ * @returns whether async_operations search is needed
30
30
  */
31
31
  searchAsync() {
32
32
  const { not, term, terms } = this.dbQueryParameters;
33
33
  return (!!(not?.asyncOperationId || term?.asyncOperationId || terms?.asyncOperationId));
34
34
  }
35
35
  /**
36
- * check if joined async_ops table search is needed
36
+ * check if joined parent execution table search is needed
37
37
  *
38
- * @returns whether collection search is needed
38
+ * @returns whether parent execution search is needed
39
39
  */
40
40
  searchParent() {
41
41
  const { not, term, terms } = this.dbQueryParameters;
@@ -101,7 +101,7 @@ class ExecutionSearch extends BaseSearch_1.BaseSearch {
101
101
  [countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.arn`, `%${infix}%`));
102
102
  }
103
103
  if (prefix) {
104
- [countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.arn`, `%${prefix}%`));
104
+ [countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.arn`, `${prefix}%`));
105
105
  }
106
106
  }
107
107
  /**
@@ -112,6 +112,7 @@ class ExecutionSearch extends BaseSearch_1.BaseSearch {
112
112
  */
113
113
  translatePostgresRecordsToApiRecords(pgRecords) {
114
114
  log.debug(`translatePostgresRecordsToApiRecords number of records ${pgRecords.length} `);
115
+ const { fields } = this.dbQueryParameters;
115
116
  const apiRecords = pgRecords.map((executionRecord) => {
116
117
  const { collectionName, collectionVersion, asyncOperationId, parentArn } = executionRecord;
117
118
  const collectionId = collectionName && collectionVersion
@@ -122,9 +123,7 @@ class ExecutionSearch extends BaseSearch_1.BaseSearch {
122
123
  asyncOperationId,
123
124
  parentArn,
124
125
  });
125
- return this.dbQueryParameters.fields
126
- ? (0, pick_1.default)(apiRecord, this.dbQueryParameters.fields)
127
- : apiRecord;
126
+ return fields ? (0, pick_1.default)(apiRecord, fields) : apiRecord;
128
127
  });
129
128
  return apiRecords;
130
129
  }
@@ -5,14 +5,9 @@ import { BaseSearch } from './BaseSearch';
5
5
  import { DbQueryParameters, QueryEvent } from '../types/search';
6
6
  import { PostgresGranuleRecord } from '../types/granule';
7
7
  interface GranuleRecord extends BaseRecord, PostgresGranuleRecord {
8
- cumulus_id: number;
9
- updated_at: Date;
10
- collection_cumulus_id: number;
11
8
  collectionName: string;
12
9
  collectionVersion: string;
13
- pdr_cumulus_id: number;
14
10
  pdrName?: string;
15
- provider_cumulus_id?: number;
16
11
  providerName?: string;
17
12
  }
18
13
  /**
@@ -43,13 +38,26 @@ export declare class GranuleSearch extends BaseSearch {
43
38
  searchQuery: Knex.QueryBuilder;
44
39
  dbQueryParameters?: DbQueryParameters;
45
40
  }): void;
41
+ /**
42
+ * Build the search query for active collections.
43
+ * If time params are specified the query will search granules that have been updated
44
+ * in that time frame. If granuleId or providerId are provided, it will filter those as well.
45
+ *
46
+ * @param knex - DB client
47
+ * @returns queries for getting count and search result
48
+ */
49
+ buildSearchForActiveCollections(knex: Knex): {
50
+ countQuery: Knex.QueryBuilder;
51
+ searchQuery: Knex.QueryBuilder;
52
+ };
46
53
  /**
47
54
  * Translate postgres records to api records
48
55
  *
49
56
  * @param pgRecords - postgres records returned from query
57
+ * @param knex - DB client
50
58
  * @returns translated api records
51
59
  */
52
- protected translatePostgresRecordsToApiRecords(pgRecords: GranuleRecord[]): Partial<ApiGranuleRecord>[];
60
+ protected translatePostgresRecordsToApiRecords(pgRecords: GranuleRecord[], knex: Knex): Promise<Partial<ApiGranuleRecord>[]>;
53
61
  }
54
62
  export {};
55
63
  //# sourceMappingURL=GranuleSearch.d.ts.map
@@ -10,6 +10,8 @@ const logger_1 = __importDefault(require("@cumulus/logger"));
10
10
  const BaseSearch_1 = require("./BaseSearch");
11
11
  const granules_1 = require("../translate/granules");
12
12
  const tables_1 = require("../tables");
13
+ const file_1 = require("../models/file");
14
+ const execution_1 = require("../lib/execution");
13
15
  const log = new logger_1.default({ sender: '@cumulus/db/GranuleSearch' });
14
16
  /**
15
17
  * Class to build and execute db search query for granules
@@ -78,14 +80,56 @@ class GranuleSearch extends BaseSearch_1.BaseSearch {
78
80
  [countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.granule_id`, `${prefix}%`));
79
81
  }
80
82
  }
83
+ /**
84
+ * Build the search query for active collections.
85
+ * If time params are specified the query will search granules that have been updated
86
+ * in that time frame. If granuleId or providerId are provided, it will filter those as well.
87
+ *
88
+ * @param knex - DB client
89
+ * @returns queries for getting count and search result
90
+ */
91
+ buildSearchForActiveCollections(knex) {
92
+ const { countQuery, searchQuery } = this.buildBasicQuery(knex);
93
+ this.buildTermQuery({ countQuery, searchQuery });
94
+ this.buildTermsQuery({ countQuery, searchQuery });
95
+ this.buildRangeQuery({ knex, countQuery, searchQuery });
96
+ log.debug(`buildSearchForActiveCollections returns countQuery: ${countQuery?.toSQL().sql}, searchQuery: ${searchQuery.toSQL().sql}`);
97
+ return { countQuery, searchQuery };
98
+ }
81
99
  /**
82
100
  * Translate postgres records to api records
83
101
  *
84
102
  * @param pgRecords - postgres records returned from query
103
+ * @param knex - DB client
85
104
  * @returns translated api records
86
105
  */
87
- translatePostgresRecordsToApiRecords(pgRecords) {
106
+ async translatePostgresRecordsToApiRecords(pgRecords, knex) {
88
107
  log.debug(`translatePostgresRecordsToApiRecords number of records ${pgRecords.length} `);
108
+ const { fields, includeFullRecord } = this.dbQueryParameters;
109
+ const fileMapping = {};
110
+ const executionMapping = {};
111
+ const cumulusIds = pgRecords.map((record) => record.cumulus_id);
112
+ if (includeFullRecord) {
113
+ //get Files
114
+ const fileModel = new file_1.FilePgModel();
115
+ const files = await fileModel.searchByGranuleCumulusIds(knex, cumulusIds);
116
+ files.forEach((file) => {
117
+ if (!(file.granule_cumulus_id in fileMapping)) {
118
+ fileMapping[file.granule_cumulus_id] = [];
119
+ }
120
+ fileMapping[file.granule_cumulus_id].push(file);
121
+ });
122
+ //get Executions
123
+ const executions = await (0, execution_1.getExecutionInfoByGranuleCumulusIds)({
124
+ knexOrTransaction: knex,
125
+ granuleCumulusIds: cumulusIds,
126
+ });
127
+ executions.forEach((execution) => {
128
+ if (!(execution.granule_cumulus_id in executionMapping)) {
129
+ executionMapping[execution.granule_cumulus_id] = execution;
130
+ }
131
+ });
132
+ }
89
133
  const apiRecords = pgRecords.map((item) => {
90
134
  const granulePgRecord = item;
91
135
  const collectionPgRecord = {
@@ -93,14 +137,21 @@ class GranuleSearch extends BaseSearch_1.BaseSearch {
93
137
  name: item.collectionName,
94
138
  version: item.collectionVersion,
95
139
  };
140
+ const executionUrls = executionMapping[item.cumulus_id]?.url
141
+ ? [{ url: executionMapping[item.cumulus_id].url }]
142
+ : [];
96
143
  const pdr = item.pdrName ? { name: item.pdrName } : undefined;
97
144
  const providerPgRecord = item.providerName ? { name: item.providerName } : undefined;
145
+ const fileRecords = fileMapping[granulePgRecord.cumulus_id] || [];
98
146
  const apiRecord = (0, granules_1.translatePostgresGranuleToApiGranuleWithoutDbQuery)({
99
- granulePgRecord, collectionPgRecord, pdr, providerPgRecord,
147
+ granulePgRecord,
148
+ collectionPgRecord,
149
+ pdr,
150
+ providerPgRecord,
151
+ files: fileRecords,
152
+ executionUrls,
100
153
  });
101
- return this.dbQueryParameters.fields
102
- ? (0, pick_1.default)(apiRecord, this.dbQueryParameters.fields)
103
- : apiRecord;
154
+ return fields ? (0, pick_1.default)(apiRecord, fields) : apiRecord;
104
155
  });
105
156
  return apiRecords;
106
157
  }