@cumulus/db 9.2.4 → 9.4.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.
package/dist/config.js CHANGED
@@ -103,7 +103,7 @@ exports.getConnectionConfig = async ({ env, secretsManager = new aws_sdk_1.defau
103
103
  * @returns {Promise<Knex.Config>} a Knex configuration object
104
104
  */
105
105
  exports.getKnexConfig = async ({ env = process.env, secretsManager = new aws_sdk_1.default.SecretsManager(), } = {}) => {
106
- var _a, _b, _c;
106
+ var _a, _b, _c, _d, _e, _f, _g;
107
107
  const knexConfig = {
108
108
  client: 'pg',
109
109
  connection: await exports.getConnectionConfig({ env, secretsManager }),
@@ -116,11 +116,16 @@ exports.getKnexConfig = async ({ env = process.env, secretsManager = new aws_sdk
116
116
  // ts-ignore as https://github.com/knex/knex/blob/master/types/index.d.ts#L1886
117
117
  // is improperly typed.
118
118
  //@ts-ignore
119
- createTimeoutMillis: Number.parseInt((_c = env.createTimeoutMillis) !== null && _c !== void 0 ? _c : '60000', 10),
119
+ acquireTimeoutMillis: Number.parseInt((_c = env.acquireTimeoutMillis) !== null && _c !== void 0 ? _c : '90000', 10),
120
+ createRetryIntervalMillis: Number.parseInt((_d = env.createRetryIntervalMillis) !== null && _d !== void 0 ? _d : '30000', 10),
121
+ createTimeoutMillis: Number.parseInt((_e = env.createTimeoutMillis) !== null && _e !== void 0 ? _e : '20000', 10),
122
+ destroyTimeoutMillis: Number.parseInt((_f = env.destroyTimeoutMillis) !== null && _f !== void 0 ? _f : '5000', 10),
123
+ reapIntervalMillis: Number.parseInt((_g = env.reapIntervalMillis) !== null && _g !== void 0 ? _g : '1000', 10),
124
+ propagateCreateError: false,
120
125
  },
121
126
  };
122
- knexConfig.acquireConnectionTimeout = env.knexAcquireConnectionTimeout
123
- ? Number(env.knexAcquireConnectionTimeout)
127
+ knexConfig.acquireConnectionTimeout = env.acquireTimeoutMillis
128
+ ? Number(env.acquireTimeoutMillis + 1000)
124
129
  : 60000;
125
130
  if (env.migrationDir) {
126
131
  knexConfig.migrations = {
@@ -1,9 +1,7 @@
1
1
  /// <reference types="node" />
2
2
  import AWS from 'aws-sdk';
3
3
  import Knex from 'knex';
4
- export declare const queryHeartbeat: ({ knex, }: {
5
- knex: Knex;
6
- }) => Promise<void>;
4
+ import Logger from '@cumulus/logger';
7
5
  /**
8
6
  * Given a NodeJS.ProcessEnv with configuration values, build and return
9
7
  * Knex client
@@ -36,15 +34,11 @@ export declare const queryHeartbeat: ({ knex, }: {
36
34
  * acquireConnectionTimeout connection timeout
37
35
  * @param {string} [params.env.migrationDir] - Directory to look in for
38
36
  * migrations
39
- * @param {string} params.env.dbHeartBeat - Configuration option if set to 'true'
40
- * causes the method to test the connection
41
- * before returning a knex object. Will retry
42
- * on KnexTimeOutError due possible RDS serverless
43
- * deployment architechtures
44
37
  * @returns {Promise<Knex>} a Knex configuration object that has returned at least one query
45
38
  */
46
- export declare const getKnexClient: ({ env, secretsManager, }?: {
39
+ export declare const getKnexClient: ({ env, secretsManager, knexLogger, }?: {
47
40
  env?: NodeJS.ProcessEnv | undefined;
48
41
  secretsManager?: AWS.SecretsManager | undefined;
42
+ knexLogger?: Logger | undefined;
49
43
  }) => Promise<Knex>;
50
44
  //# sourceMappingURL=connection.d.ts.map
@@ -3,26 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getKnexClient = exports.queryHeartbeat = void 0;
6
+ exports.getKnexClient = void 0;
7
7
  const aws_sdk_1 = __importDefault(require("aws-sdk"));
8
8
  const knex_1 = __importDefault(require("knex"));
9
- const p_retry_1 = __importDefault(require("p-retry"));
10
9
  const logger_1 = __importDefault(require("@cumulus/logger"));
11
10
  const config_1 = require("./config");
12
11
  const log = new logger_1.default({ sender: '@cumulus/db/connection' });
13
- exports.queryHeartbeat = async ({ knex, }) => await p_retry_1.default(async () => {
14
- log.info('Sending Heartbeat Query');
15
- await knex.raw('SELECT 1');
16
- log.info('Heartbeat succeeded');
17
- }, {
18
- onFailedAttempt: (error) => {
19
- if (error.name !== 'KnexTimeoutError') {
20
- throw error;
21
- }
22
- log.warn(`Failed intial attempt at RDS DB connection due to ${error.name}`);
23
- },
24
- retries: 1,
25
- });
26
12
  /**
27
13
  * Given a NodeJS.ProcessEnv with configuration values, build and return
28
14
  * Knex client
@@ -55,25 +41,19 @@ exports.queryHeartbeat = async ({ knex, }) => await p_retry_1.default(async () =
55
41
  * acquireConnectionTimeout connection timeout
56
42
  * @param {string} [params.env.migrationDir] - Directory to look in for
57
43
  * migrations
58
- * @param {string} params.env.dbHeartBeat - Configuration option if set to 'true'
59
- * causes the method to test the connection
60
- * before returning a knex object. Will retry
61
- * on KnexTimeOutError due possible RDS serverless
62
- * deployment architechtures
63
44
  * @returns {Promise<Knex>} a Knex configuration object that has returned at least one query
64
45
  */
65
- exports.getKnexClient = async ({ env = process.env, secretsManager = new aws_sdk_1.default.SecretsManager(), } = {}) => {
46
+ exports.getKnexClient = async ({ env = process.env, secretsManager = new aws_sdk_1.default.SecretsManager(), knexLogger = log, } = {}) => {
66
47
  const knexConfig = await config_1.getKnexConfig({ env, secretsManager });
67
48
  const knex = knex_1.default(knexConfig);
68
- if (env.dbHeartBeat === 'true') {
69
- try {
70
- await exports.queryHeartbeat({ knex });
71
- }
72
- catch (error) {
73
- knex.destroy();
74
- throw error;
75
- }
76
- }
49
+ //@ts-ignore
50
+ // context is an internal object that isn't typed
51
+ // this is needed to force tarn to log per-retry failures
52
+ // and allow propagateCreateError to be set `false`
53
+ knex.context.client.pool.on('createFail', (_, error) => {
54
+ knexLogger.warn('knex failed on attempted connection', error);
55
+ throw error;
56
+ });
77
57
  return knex;
78
58
  };
79
59
  //# sourceMappingURL=connection.js.map
package/dist/index.d.ts CHANGED
@@ -17,10 +17,11 @@ export { translateApiFiletoPostgresFile, } from './translate/file';
17
17
  export { translateApiCollectionToPostgresCollection } from './translate/collections';
18
18
  export { translateApiProviderToPostgresProvider, } from './translate/providers';
19
19
  export { translateApiRuleToPostgresRule } from './translate/rules';
20
- export { translateApiExecutionToPostgresExecution } from './translate/executions';
20
+ export { translateApiExecutionToPostgresExecution, translatePostgresExecutionToApiExecution, } from './translate/executions';
21
21
  export { translateApiGranuleToPostgresGranule } from './translate/granules';
22
22
  export { translateApiPdrToPostgresPdr } from './translate/pdrs';
23
- export { upsertGranuleWithExecutionJoinRecord, } from './lib/granule';
23
+ export { executionArnsFromGranuleIdsAndWorkflowNames, newestExecutionArnFromGranuleIdWorkflowName, getWorkflowNameIntersectFromGranuleIds, } from './lib/execution';
24
+ export { getApiGranuleCumulusIds, getApiGranuleExecutionCumulusIds, upsertGranuleWithExecutionJoinRecord, } from './lib/granule';
24
25
  export { AsyncOperationPgModel } from './models/async_operation';
25
26
  export { BasePgModel } from './models/base';
26
27
  export { CollectionPgModel } from './models/collection';
package/dist/index.js CHANGED
@@ -36,11 +36,18 @@ var rules_1 = require("./translate/rules");
36
36
  Object.defineProperty(exports, "translateApiRuleToPostgresRule", { enumerable: true, get: function () { return rules_1.translateApiRuleToPostgresRule; } });
37
37
  var executions_1 = require("./translate/executions");
38
38
  Object.defineProperty(exports, "translateApiExecutionToPostgresExecution", { enumerable: true, get: function () { return executions_1.translateApiExecutionToPostgresExecution; } });
39
+ Object.defineProperty(exports, "translatePostgresExecutionToApiExecution", { enumerable: true, get: function () { return executions_1.translatePostgresExecutionToApiExecution; } });
39
40
  var granules_1 = require("./translate/granules");
40
41
  Object.defineProperty(exports, "translateApiGranuleToPostgresGranule", { enumerable: true, get: function () { return granules_1.translateApiGranuleToPostgresGranule; } });
41
42
  var pdrs_1 = require("./translate/pdrs");
42
43
  Object.defineProperty(exports, "translateApiPdrToPostgresPdr", { enumerable: true, get: function () { return pdrs_1.translateApiPdrToPostgresPdr; } });
44
+ var execution_1 = require("./lib/execution");
45
+ Object.defineProperty(exports, "executionArnsFromGranuleIdsAndWorkflowNames", { enumerable: true, get: function () { return execution_1.executionArnsFromGranuleIdsAndWorkflowNames; } });
46
+ Object.defineProperty(exports, "newestExecutionArnFromGranuleIdWorkflowName", { enumerable: true, get: function () { return execution_1.newestExecutionArnFromGranuleIdWorkflowName; } });
47
+ Object.defineProperty(exports, "getWorkflowNameIntersectFromGranuleIds", { enumerable: true, get: function () { return execution_1.getWorkflowNameIntersectFromGranuleIds; } });
43
48
  var granule_1 = require("./lib/granule");
49
+ Object.defineProperty(exports, "getApiGranuleCumulusIds", { enumerable: true, get: function () { return granule_1.getApiGranuleCumulusIds; } });
50
+ Object.defineProperty(exports, "getApiGranuleExecutionCumulusIds", { enumerable: true, get: function () { return granule_1.getApiGranuleExecutionCumulusIds; } });
44
51
  Object.defineProperty(exports, "upsertGranuleWithExecutionJoinRecord", { enumerable: true, get: function () { return granule_1.upsertGranuleWithExecutionJoinRecord; } });
45
52
  var async_operation_1 = require("./models/async_operation");
46
53
  Object.defineProperty(exports, "AsyncOperationPgModel", { enumerable: true, get: function () { return async_operation_1.AsyncOperationPgModel; } });
@@ -48,8 +55,8 @@ var base_1 = require("./models/base");
48
55
  Object.defineProperty(exports, "BasePgModel", { enumerable: true, get: function () { return base_1.BasePgModel; } });
49
56
  var collection_1 = require("./models/collection");
50
57
  Object.defineProperty(exports, "CollectionPgModel", { enumerable: true, get: function () { return collection_1.CollectionPgModel; } });
51
- var execution_1 = require("./models/execution");
52
- Object.defineProperty(exports, "ExecutionPgModel", { enumerable: true, get: function () { return execution_1.ExecutionPgModel; } });
58
+ var execution_2 = require("./models/execution");
59
+ Object.defineProperty(exports, "ExecutionPgModel", { enumerable: true, get: function () { return execution_2.ExecutionPgModel; } });
53
60
  var file_2 = require("./models/file");
54
61
  Object.defineProperty(exports, "FilePgModel", { enumerable: true, get: function () { return file_2.FilePgModel; } });
55
62
  var granule_2 = require("./models/granule");
@@ -0,0 +1,36 @@
1
+ import Knex from 'knex';
2
+ export interface arnRecord {
3
+ arn: string;
4
+ }
5
+ /**
6
+ * Returns a list of executionArns sorted by most recent first, for an input
7
+ * list of granuleIds and workflowNames.
8
+ *
9
+ * @param {Knex} knex - DB Client
10
+ * @param {string[]} granuleIds - Array of granuleIds
11
+ * @param {string[]} workflowNames - Array of workflow names
12
+ * @returns {Promise<arnRecord[]>} - Array of arn objects with the most recent first.
13
+ */
14
+ export declare const executionArnsFromGranuleIdsAndWorkflowNames: (knex: Knex, granuleIds: string[], workflowNames: string[]) => Promise<arnRecord[]>;
15
+ /**
16
+ * convenience function to return a single executionArn string for a intput
17
+ * granuleId and workflowName.
18
+ *
19
+ * @param {string} granuleId - granuleIds
20
+ * @param {string} workflowName - workflow name
21
+ * @returns {Promise<string>} - most recent exectutionArn for input parameters.
22
+ * @throws {RecordNotFound}
23
+ */
24
+ export declare const newestExecutionArnFromGranuleIdWorkflowName: (granuleId: string, workflowName: string, testKnex: Knex | undefined) => Promise<string>;
25
+ /**
26
+ * Returns the intersect of workflow names that exist for all granule ids that are passed in
27
+ * When a single granule is passed in, workflow names are sorted by most recent first
28
+ *
29
+ * @param {Knex | Knex.Transaction} knexOrTransaction - DB Client or transaction
30
+ * @param {Array<string>} granuleCumulusIds - Array of granule cumulus ids to query
31
+ * @returns {Promise<string[]>} - Array consisting of workflow names common to all granules.
32
+ * Sorted by most recent when array includes a single granule
33
+ * @throws {RecordNotFound}
34
+ */
35
+ export declare const getWorkflowNameIntersectFromGranuleIds: (knexOrTransaction: Knex | Knex.Transaction, granuleCumulusIds: Array<number> | number) => Promise<Array<string>>;
36
+ //# sourceMappingURL=execution.d.ts.map
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWorkflowNameIntersectFromGranuleIds = exports.newestExecutionArnFromGranuleIdWorkflowName = exports.executionArnsFromGranuleIdsAndWorkflowNames = void 0;
4
+ const errors_1 = require("@cumulus/errors");
5
+ const tables_1 = require("../tables");
6
+ const Logger = require('@cumulus/logger');
7
+ const { getKnexClient } = require('../connection');
8
+ const log = new Logger({ sender: '@cumulus/db/lib/execution' });
9
+ /**
10
+ * Returns a list of executionArns sorted by most recent first, for an input
11
+ * list of granuleIds and workflowNames.
12
+ *
13
+ * @param {Knex} knex - DB Client
14
+ * @param {string[]} granuleIds - Array of granuleIds
15
+ * @param {string[]} workflowNames - Array of workflow names
16
+ * @returns {Promise<arnRecord[]>} - Array of arn objects with the most recent first.
17
+ */
18
+ exports.executionArnsFromGranuleIdsAndWorkflowNames = (knex, granuleIds, workflowNames) => knex
19
+ .select(`${tables_1.tableNames.executions}.arn`)
20
+ .from(tables_1.tableNames.executions)
21
+ .join(tables_1.tableNames.granulesExecutions, `${tables_1.tableNames.executions}.cumulus_id`, `${tables_1.tableNames.granulesExecutions}.execution_cumulus_id`)
22
+ .join(tables_1.tableNames.granules, `${tables_1.tableNames.granules}.cumulus_id`, `${tables_1.tableNames.granulesExecutions}.granule_cumulus_id`)
23
+ .whereIn(`${tables_1.tableNames.granules}.granule_id`, granuleIds)
24
+ .whereIn(`${tables_1.tableNames.executions}.workflow_name`, workflowNames)
25
+ .orderBy(`${tables_1.tableNames.executions}.timestamp`, 'desc');
26
+ /**
27
+ * convenience function to return a single executionArn string for a intput
28
+ * granuleId and workflowName.
29
+ *
30
+ * @param {string} granuleId - granuleIds
31
+ * @param {string} workflowName - workflow name
32
+ * @returns {Promise<string>} - most recent exectutionArn for input parameters.
33
+ * @throws {RecordNotFound}
34
+ */
35
+ exports.newestExecutionArnFromGranuleIdWorkflowName = async (granuleId, workflowName, testKnex) => {
36
+ try {
37
+ const knex = testKnex !== null && testKnex !== void 0 ? testKnex : await getKnexClient({ env: process.env });
38
+ const executions = await exports.executionArnsFromGranuleIdsAndWorkflowNames(knex, [granuleId], [workflowName]);
39
+ if (executions.length === 0) {
40
+ throw new errors_1.RecordDoesNotExist(`No executionArns found for granuleId:${granuleId} running workflow:${workflowName}`);
41
+ }
42
+ return executions[0].arn;
43
+ }
44
+ catch (error) {
45
+ log.error(error);
46
+ throw error;
47
+ }
48
+ };
49
+ /**
50
+ * Returns the intersect of workflow names that exist for all granule ids that are passed in
51
+ * When a single granule is passed in, workflow names are sorted by most recent first
52
+ *
53
+ * @param {Knex | Knex.Transaction} knexOrTransaction - DB Client or transaction
54
+ * @param {Array<string>} granuleCumulusIds - Array of granule cumulus ids to query
55
+ * @returns {Promise<string[]>} - Array consisting of workflow names common to all granules.
56
+ * Sorted by most recent when array includes a single granule
57
+ * @throws {RecordNotFound}
58
+ */
59
+ exports.getWorkflowNameIntersectFromGranuleIds = async (knexOrTransaction, granuleCumulusIds) => {
60
+ const granuleCumulusIdsArray = [granuleCumulusIds].flat();
61
+ const numberOfGranules = granuleCumulusIdsArray.length;
62
+ const { executions: executionsTable, granulesExecutions: granulesExecutionsTable } = tables_1.tableNames;
63
+ const aggregatedWorkflowCounts = await knexOrTransaction(executionsTable)
64
+ .select('workflow_name')
65
+ .countDistinct('granule_cumulus_id')
66
+ .innerJoin(granulesExecutionsTable, `${executionsTable}.cumulus_id`, `${granulesExecutionsTable}.execution_cumulus_id`)
67
+ .whereIn('granule_cumulus_id', granuleCumulusIdsArray)
68
+ .groupBy('workflow_name')
69
+ .havingRaw('count(distinct granule_cumulus_id) = ?', [numberOfGranules])
70
+ .modify((queryBuilder) => {
71
+ if (numberOfGranules === 1) {
72
+ queryBuilder.groupBy('timestamp')
73
+ .orderBy('timestamp', 'desc');
74
+ }
75
+ });
76
+ return aggregatedWorkflowCounts
77
+ .map((workflowCounts) => workflowCounts.workflow_name);
78
+ };
79
+ //# sourceMappingURL=execution.js.map
@@ -1,5 +1,6 @@
1
1
  import Knex from 'knex';
2
2
  import { PostgresGranule } from '../types/granule';
3
+ import { CollectionPgModel } from '../models/collection';
3
4
  import { GranulePgModel } from '../models/granule';
4
5
  import { GranulesExecutionsPgModel } from '../models/granules-executions';
5
6
  /**
@@ -14,4 +15,34 @@ import { GranulesExecutionsPgModel } from '../models/granules-executions';
14
15
  * @returns {Promise<number[]>}
15
16
  */
16
17
  export declare const upsertGranuleWithExecutionJoinRecord: (knexTransaction: Knex.Transaction, granule: PostgresGranule, executionCumulusId?: number | undefined, granulePgModel?: GranulePgModel, granulesExecutionsPgModel?: GranulesExecutionsPgModel) => Promise<number[]>;
18
+ /**
19
+ * Get cumulus IDs for list of granules
20
+ *
21
+ * @param {Knex | Knex.Transaction} knexOrTransaction -
22
+ * DB client or transaction
23
+ * @param {Array<Object>} granules - array of granules with collectionId and granuleId
24
+ * @param {Object} [collectionPgModel] - Collection PG model class instance
25
+ * @param {Object} [granulePgModel] - Granule PG model class instance
26
+ * @returns {Promise<number[]>}
27
+ */
28
+ export declare const getApiGranuleCumulusIds: (knexOrTransaction: Knex | Knex.Transaction, granules: Array<{
29
+ collectionId: string;
30
+ granuleId: string;
31
+ }>, collectionPgModel?: CollectionPgModel, granulePgModel?: GranulePgModel) => Promise<number[]>;
32
+ /**
33
+ * Get cumulus IDs for all executions associated to a set of granules
34
+ *
35
+ * @param {Knex | Knex.Transaction} knexOrTransaction -
36
+ * DB client or transaction
37
+ * @param {Array<Object>} granules - array of granules with collectionId and granuleId
38
+ * @param {Object} [collectionPgModel] - Collection PG model class instance
39
+ * @param {Object} [granulePgModel] - Granule PG model class instance
40
+ * @param {Object} [granulesExecutionsPgModel]
41
+ * Granules/executions PG model class instance
42
+ * @returns {Promise<number[]>}
43
+ */
44
+ export declare const getApiGranuleExecutionCumulusIds: (knexOrTransaction: Knex | Knex.Transaction, granules: Array<{
45
+ collectionId: string;
46
+ granuleId: string;
47
+ }>, collectionPgModel?: CollectionPgModel, granulePgModel?: GranulePgModel, granulesExecutionsPgModel?: GranulesExecutionsPgModel) => Promise<Array<number>>;
17
48
  //# sourceMappingURL=granule.d.ts.map
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.upsertGranuleWithExecutionJoinRecord = void 0;
3
+ exports.getApiGranuleExecutionCumulusIds = exports.getApiGranuleCumulusIds = exports.upsertGranuleWithExecutionJoinRecord = void 0;
4
+ const collection_1 = require("../models/collection");
4
5
  const granule_1 = require("../models/granule");
5
6
  const granules_executions_1 = require("../models/granules-executions");
7
+ const { deconstructCollectionId } = require('@cumulus/message/Collections');
6
8
  /**
7
9
  * Upsert a granule and a record in the granules/executions join table.
8
10
  *
@@ -31,4 +33,49 @@ exports.upsertGranuleWithExecutionJoinRecord = async (knexTransaction, granule,
31
33
  }
32
34
  return [granuleCumulusId];
33
35
  };
36
+ /**
37
+ * Get cumulus IDs for list of granules
38
+ *
39
+ * @param {Knex | Knex.Transaction} knexOrTransaction -
40
+ * DB client or transaction
41
+ * @param {Array<Object>} granules - array of granules with collectionId and granuleId
42
+ * @param {Object} [collectionPgModel] - Collection PG model class instance
43
+ * @param {Object} [granulePgModel] - Granule PG model class instance
44
+ * @returns {Promise<number[]>}
45
+ */
46
+ exports.getApiGranuleCumulusIds = async (knexOrTransaction, granules, collectionPgModel = new collection_1.CollectionPgModel(), granulePgModel = new granule_1.GranulePgModel()) => {
47
+ const collectionMap = {};
48
+ const granuleCumulusIds = await Promise.all(granules.map(async (granule) => {
49
+ const { collectionId } = granule;
50
+ let collectionCumulusId = collectionMap[collectionId];
51
+ if (!collectionCumulusId) {
52
+ const { name, version } = deconstructCollectionId(collectionId);
53
+ collectionCumulusId = await collectionPgModel.getRecordCumulusId(knexOrTransaction, { name, version });
54
+ collectionMap[collectionId] = collectionCumulusId;
55
+ }
56
+ return await granulePgModel.getRecordCumulusId(knexOrTransaction, {
57
+ granule_id: granule.granuleId,
58
+ collection_cumulus_id: collectionCumulusId,
59
+ });
60
+ }));
61
+ return [...new Set(granuleCumulusIds)];
62
+ };
63
+ /**
64
+ * Get cumulus IDs for all executions associated to a set of granules
65
+ *
66
+ * @param {Knex | Knex.Transaction} knexOrTransaction -
67
+ * DB client or transaction
68
+ * @param {Array<Object>} granules - array of granules with collectionId and granuleId
69
+ * @param {Object} [collectionPgModel] - Collection PG model class instance
70
+ * @param {Object} [granulePgModel] - Granule PG model class instance
71
+ * @param {Object} [granulesExecutionsPgModel]
72
+ * Granules/executions PG model class instance
73
+ * @returns {Promise<number[]>}
74
+ */
75
+ exports.getApiGranuleExecutionCumulusIds = async (knexOrTransaction, granules, collectionPgModel = new collection_1.CollectionPgModel(), granulePgModel = new granule_1.GranulePgModel(), granulesExecutionsPgModel = new granules_executions_1.GranulesExecutionsPgModel()) => {
76
+ const granuleCumulusIds = await exports.getApiGranuleCumulusIds(knexOrTransaction, granules, collectionPgModel, granulePgModel);
77
+ const executionCumulusIds = await granulesExecutionsPgModel
78
+ .searchByGranuleCumulusIds(knexOrTransaction, granuleCumulusIds);
79
+ return executionCumulusIds;
80
+ };
34
81
  //# sourceMappingURL=granule.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Returns an array of sort fields and their order for use with PostGres
3
+ * modified from @cumulus/es-client/queries
4
+ *
5
+ * @param {Object} params - sort params
6
+ */
7
+ export declare const getSortFields: (params: {
8
+ sort_by?: string;
9
+ order?: string;
10
+ sort_key?: Array<string>;
11
+ }) => {
12
+ [x: string]: {
13
+ order: string;
14
+ };
15
+ }[];
16
+ //# sourceMappingURL=sort.d.ts.map
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ /**
3
+ * Returns an array of sort fields and their order for use with PostGres
4
+ * modified from @cumulus/es-client/queries
5
+ *
6
+ * @param {Object} params - sort params
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getSortFields = void 0;
10
+ exports.getSortFields = (params) => {
11
+ let sort;
12
+ const { sort_by: sortBy, order, sort_key: sortKey } = params;
13
+ if (sortBy && order) {
14
+ const sortField = sortBy;
15
+ sort = [{ [sortField]: { order: order } }];
16
+ }
17
+ else if (sortKey && Array.isArray(sortKey)) {
18
+ sort = sortKey.map((key) => {
19
+ const sortField = key.replace(/^[+-]/, '');
20
+ return { [sortField]: { order: key.startsWith('-') ? 'desc' : 'asc' } };
21
+ });
22
+ }
23
+ else {
24
+ sort = [{ timestamp: { order: 'desc' } }];
25
+ }
26
+ return sort;
27
+ };
28
+ //# sourceMappingURL=sort.js.map
@@ -36,6 +36,16 @@ declare class BasePgModel<ItemType, RecordType extends {
36
36
  * @returns {Promise<number>} The cumulus_id of the returned record
37
37
  */
38
38
  getRecordCumulusId(knexOrTransaction: Knex | Knex.Transaction, whereClause: Partial<RecordType>): Promise<number>;
39
+ /**
40
+ * Get cumulus_id column value for multiple records in Postgres
41
+ *
42
+ * @param {Knex | Knex.Transaction} knexOrTransaction -
43
+ * DB client or transaction
44
+ * @param {Array<keyof RecordType>} columnNames - column names for whereIn query
45
+ * @param {Array<string>} values - record values for whereIn query
46
+ * @returns {Promise<Array<number>>} An array of cumulus_ids for the returned records
47
+ */
48
+ getRecordsCumulusIds(knexOrTransaction: Knex | Knex.Transaction, columnNames: Array<keyof RecordType>, values: Array<any>): Promise<Array<number>>;
39
49
  /**
40
50
  * Checks if an item is present in Postgres
41
51
  *
@@ -67,6 +67,21 @@ class BasePgModel {
67
67
  }
68
68
  return record.cumulus_id;
69
69
  }
70
+ /**
71
+ * Get cumulus_id column value for multiple records in Postgres
72
+ *
73
+ * @param {Knex | Knex.Transaction} knexOrTransaction -
74
+ * DB client or transaction
75
+ * @param {Array<keyof RecordType>} columnNames - column names for whereIn query
76
+ * @param {Array<string>} values - record values for whereIn query
77
+ * @returns {Promise<Array<number>>} An array of cumulus_ids for the returned records
78
+ */
79
+ async getRecordsCumulusIds(knexOrTransaction, columnNames, values) {
80
+ const records = await knexOrTransaction(this.tableName)
81
+ .select('cumulus_id')
82
+ .whereIn(columnNames, values);
83
+ return records.map((record) => record.cumulus_id);
84
+ }
70
85
  /**
71
86
  * Checks if an item is present in Postgres
72
87
  *
@@ -6,7 +6,7 @@ declare class CollectionPgModel extends BasePgModel<PostgresCollection, Postgres
6
6
  upsert(knexOrTransaction: Knex | Knex.Transaction, collection: PostgresCollection): Knex.QueryBuilder<any, {
7
7
  _base: any;
8
8
  _hasSelection: true;
9
- _keys: "name" | "version" | "cumulus_id";
9
+ _keys: "name" | "cumulus_id" | "version";
10
10
  _aliases: {};
11
11
  _single: true;
12
12
  _intersectProps: {};
@@ -4,6 +4,22 @@ import { PostgresExecution, PostgresExecutionRecord } from '../types/execution';
4
4
  declare class ExecutionPgModel extends BasePgModel<PostgresExecution, PostgresExecutionRecord> {
5
5
  constructor();
6
6
  upsert(knexOrTrx: Knex | Knex.Transaction, execution: PostgresExecution): Promise<any[]>;
7
+ /**
8
+ * Get executions from the execution cumulus_id
9
+ *
10
+ * @param {Knex | Knex.Transaction} knexOrTrx -
11
+ * DB client or transaction
12
+ * @param {Array<number>} executionCumulusIds -
13
+ * single execution cumulus_id or array of exeuction cumulus_ids
14
+ * @param {Object} [params] - Optional object with addition params for query
15
+ * @param {number} [params.limit] - number of records to be returned
16
+ * @param {number} [params.offset] - record offset
17
+ * @returns {Promise<Array<number>>} An array of exeuctions
18
+ */
19
+ searchByCumulusIds(knexOrTrx: Knex | Knex.Transaction, executionCumulusIds: Array<number> | number, params: {
20
+ limit: number;
21
+ offset: number;
22
+ }): Promise<Array<number>>;
7
23
  }
8
24
  export { ExecutionPgModel };
9
25
  //# sourceMappingURL=execution.d.ts.map
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ExecutionPgModel = void 0;
4
4
  const base_1 = require("./base");
5
5
  const tables_1 = require("../tables");
6
+ const sort_1 = require("../lib/sort");
6
7
  class ExecutionPgModel extends base_1.BasePgModel {
7
8
  constructor() {
8
9
  super({
@@ -28,6 +29,39 @@ class ExecutionPgModel extends base_1.BasePgModel {
28
29
  .merge()
29
30
  .returning('cumulus_id');
30
31
  }
32
+ /**
33
+ * Get executions from the execution cumulus_id
34
+ *
35
+ * @param {Knex | Knex.Transaction} knexOrTrx -
36
+ * DB client or transaction
37
+ * @param {Array<number>} executionCumulusIds -
38
+ * single execution cumulus_id or array of exeuction cumulus_ids
39
+ * @param {Object} [params] - Optional object with addition params for query
40
+ * @param {number} [params.limit] - number of records to be returned
41
+ * @param {number} [params.offset] - record offset
42
+ * @returns {Promise<Array<number>>} An array of exeuctions
43
+ */
44
+ async searchByCumulusIds(knexOrTrx, executionCumulusIds, params) {
45
+ const { limit, offset, ...sortQueries } = params || {};
46
+ const sortFields = sort_1.getSortFields(sortQueries);
47
+ const executionCumulusIdsArray = [executionCumulusIds].flat();
48
+ const executions = await knexOrTrx(this.tableName)
49
+ .whereIn('cumulus_id', executionCumulusIdsArray)
50
+ .modify((queryBuilder) => {
51
+ if (limit)
52
+ queryBuilder.limit(limit);
53
+ if (offset)
54
+ queryBuilder.offset(offset);
55
+ if (sortFields.length >= 1) {
56
+ sortFields.forEach((sortObject) => {
57
+ const sortField = Object.keys(sortObject)[0];
58
+ const { order } = sortObject[sortField];
59
+ queryBuilder.orderBy(sortField, order);
60
+ });
61
+ }
62
+ });
63
+ return executions;
64
+ }
31
65
  }
32
66
  exports.ExecutionPgModel = ExecutionPgModel;
33
67
  //# sourceMappingURL=execution.js.map
@@ -7,6 +7,16 @@ export default class GranulesExecutionsPgModel {
7
7
  create(knexTransaction: Knex.Transaction, item: PostgresGranuleExecution): Promise<number[]>;
8
8
  exists(knexTransaction: Knex.Transaction, item: PostgresGranuleExecution): Promise<boolean>;
9
9
  upsert(knexTransaction: Knex.Transaction, item: PostgresGranuleExecution): Promise<any[]>;
10
+ /**
11
+ * Get execution_cumulus_id column values from the granule_cumulus_id
12
+ *
13
+ * @param {Knex | Knex.Transaction} knexOrTransaction -
14
+ * DB client or transaction
15
+ * @param {number | Array<number>} granuleCumulusIds -
16
+ * single granule_cumulus_id or array of granule_cumulus_ids
17
+ * @returns {Promise<Array<number>>} An array of execution_cumulus_ids
18
+ */
19
+ searchByGranuleCumulusIds(knexOrTransaction: Knex | Knex.Transaction, granuleCumulusIds: Array<number> | number): Promise<Array<number>>;
10
20
  search(knexTransaction: Knex | Knex.Transaction, query: Partial<PostgresGranuleExecution>): Knex.QueryBuilder<PostgresGranuleExecution, {
11
21
  _base: PostgresGranuleExecution;
12
22
  _hasSelection: false;
@@ -21,6 +21,23 @@ class GranulesExecutionsPgModel {
21
21
  .onConflict(['granule_cumulus_id', 'execution_cumulus_id'])
22
22
  .merge();
23
23
  }
24
+ /**
25
+ * Get execution_cumulus_id column values from the granule_cumulus_id
26
+ *
27
+ * @param {Knex | Knex.Transaction} knexOrTransaction -
28
+ * DB client or transaction
29
+ * @param {number | Array<number>} granuleCumulusIds -
30
+ * single granule_cumulus_id or array of granule_cumulus_ids
31
+ * @returns {Promise<Array<number>>} An array of execution_cumulus_ids
32
+ */
33
+ async searchByGranuleCumulusIds(knexOrTransaction, granuleCumulusIds) {
34
+ const granuleCumulusIdsArray = [granuleCumulusIds].flat();
35
+ const granuleExecutions = await knexOrTransaction(this.tableName)
36
+ .select('execution_cumulus_id')
37
+ .whereIn('granule_cumulus_id', granuleCumulusIdsArray)
38
+ .groupBy('execution_cumulus_id');
39
+ return granuleExecutions.map((granuleExecution) => granuleExecution.execution_cumulus_id);
40
+ }
24
41
  search(knexTransaction, query) {
25
42
  return knexTransaction(this.tableName)
26
43
  .where(query);
package/dist/provider.js CHANGED
@@ -26,6 +26,7 @@ exports.nullifyUndefinedProviderValues = (data) => {
26
26
  'private_key',
27
27
  'cm_key_id',
28
28
  'certificate_uri',
29
+ 'allowed_redirects',
29
30
  ];
30
31
  optionalValues.forEach((value) => {
31
32
  if (returnData[value] === undefined) {
@@ -1,9 +1,10 @@
1
1
  import Knex from 'knex';
2
2
  import { ExecutionRecord } from '@cumulus/types/api/executions';
3
- import { PostgresExecution } from '../types/execution';
3
+ import { PostgresExecution, PostgresExecutionRecord } from '../types/execution';
4
4
  import { ExecutionPgModel } from '../models/execution';
5
5
  import { CollectionPgModel } from '../models/collection';
6
6
  import { AsyncOperationPgModel } from '../models/async_operation';
7
+ export declare const translatePostgresExecutionToApiExecution: (executionRecord: PostgresExecutionRecord, knex: Knex, collectionPgModel?: CollectionPgModel, asyncOperationPgModel?: AsyncOperationPgModel, executionPgModel?: ExecutionPgModel) => Promise<ExecutionRecord>;
7
8
  /**
8
9
  * Translate execution record from Dynamo to RDS.
9
10
  *
@@ -3,12 +3,62 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.translateApiExecutionToPostgresExecution = void 0;
6
+ exports.translateApiExecutionToPostgresExecution = exports.translatePostgresExecutionToApiExecution = void 0;
7
7
  const errors_1 = require("@cumulus/errors");
8
8
  const logger_1 = __importDefault(require("@cumulus/logger"));
9
+ const util_1 = require("@cumulus/common/util");
10
+ const Collections_1 = require("@cumulus/message/Collections");
9
11
  const execution_1 = require("../models/execution");
10
12
  const collection_1 = require("../models/collection");
11
13
  const async_operation_1 = require("../models/async_operation");
14
+ exports.translatePostgresExecutionToApiExecution = async (executionRecord, knex, collectionPgModel = new collection_1.CollectionPgModel(), asyncOperationPgModel = new async_operation_1.AsyncOperationPgModel(), executionPgModel = new execution_1.ExecutionPgModel()) => {
15
+ var _a;
16
+ let parentArn;
17
+ let collectionId;
18
+ let asyncOperationId;
19
+ if (executionRecord.collection_cumulus_id) {
20
+ const collection = await collectionPgModel.get(knex, {
21
+ cumulus_id: executionRecord.collection_cumulus_id,
22
+ });
23
+ collectionId = Collections_1.constructCollectionId(collection.name, collection.version);
24
+ }
25
+ if (executionRecord.async_operation_cumulus_id) {
26
+ const asyncOperation = await asyncOperationPgModel.get(knex, {
27
+ cumulus_id: executionRecord.async_operation_cumulus_id,
28
+ });
29
+ asyncOperationId = asyncOperation.id;
30
+ }
31
+ if (executionRecord.parent_cumulus_id) {
32
+ const parentExecution = await executionPgModel.get(knex, {
33
+ cumulus_id: executionRecord.parent_cumulus_id,
34
+ });
35
+ parentArn = parentExecution.arn;
36
+ }
37
+ const postfix = executionRecord.arn.split(':').pop();
38
+ if (!postfix) {
39
+ throw new Error(`Execution ARN record ${executionRecord.arn} has an invalid postfix and API cannot generate the required 'name' field`);
40
+ }
41
+ const translatedRecord = {
42
+ name: postfix,
43
+ status: executionRecord.status,
44
+ arn: executionRecord.arn,
45
+ duration: executionRecord.duration,
46
+ error: executionRecord.error,
47
+ tasks: executionRecord.tasks,
48
+ originalPayload: executionRecord.original_payload,
49
+ finalPayload: executionRecord.final_payload,
50
+ type: executionRecord.workflow_name,
51
+ execution: executionRecord.url,
52
+ cumulusVersion: executionRecord.cumulus_version,
53
+ asyncOperationId,
54
+ collectionId,
55
+ parentArn,
56
+ createdAt: executionRecord.created_at.getTime(),
57
+ updatedAt: executionRecord.updated_at.getTime(),
58
+ timestamp: (_a = executionRecord.timestamp) === null || _a === void 0 ? void 0 : _a.getTime(),
59
+ };
60
+ return util_1.removeNilProperties(translatedRecord);
61
+ };
12
62
  /**
13
63
  * Translate execution record from Dynamo to RDS.
14
64
  *
@@ -4,7 +4,7 @@ exports.translateApiGranuleToPostgresGranule = void 0;
4
4
  const collection_1 = require("../models/collection");
5
5
  const pdr_1 = require("../models/pdr");
6
6
  const provider_1 = require("../models/provider");
7
- const { deconstructCollectionId } = require('../../../api/lib/utils');
7
+ const { deconstructCollectionId } = require('@cumulus/message/Collections');
8
8
  /**
9
9
  * Generate a Postgres granule record from a DynamoDB record.
10
10
  *
@@ -34,6 +34,7 @@ exports.translateApiProviderToPostgresProvider = async (record, encryptMethod =
34
34
  port: record.port,
35
35
  host: record.host,
36
36
  protocol: record.protocol,
37
+ allowed_redirects: record.allowedRedirects,
37
38
  username,
38
39
  password,
39
40
  });
@@ -18,6 +18,7 @@ export interface PostgresProvider {
18
18
  protocol: string;
19
19
  updated_at?: Date | null;
20
20
  username?: string | null;
21
+ allowed_redirects?: string[];
21
22
  }
22
23
  /**
23
24
  * PostgresProviderRecord
@@ -26,7 +27,7 @@ export interface PostgresProvider {
26
27
  * postgres for reading. It differs from the PostgresProvider interface in that it types
27
28
  * the autogenerated/required fields in the Postgres database as required
28
29
  */
29
- export interface PostgresProviderRecord extends PostgresProvider {
30
+ export interface PostgresProviderRecord extends Omit<PostgresProvider, 'allowed_redirects'> {
30
31
  cumulus_id: number;
31
32
  created_at: Date;
32
33
  updated_at: Date;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cumulus/db",
3
- "version": "9.2.4",
3
+ "version": "9.4.1",
4
4
  "description": "Utilities for working with the Cumulus DB",
5
5
  "license": "Apache-2.0",
6
6
  "main": "./dist/index.js",
@@ -29,12 +29,12 @@
29
29
  "node": ">=12.18.0"
30
30
  },
31
31
  "dependencies": {
32
- "@cumulus/aws-client": "9.2.4",
33
- "@cumulus/common": "9.2.4",
34
- "@cumulus/errors": "9.2.4",
35
- "@cumulus/logger": "9.2.4",
36
- "@cumulus/message": "9.2.4",
37
- "@cumulus/types": "9.2.4",
32
+ "@cumulus/aws-client": "9.4.1",
33
+ "@cumulus/common": "9.4.1",
34
+ "@cumulus/errors": "9.4.1",
35
+ "@cumulus/logger": "9.4.1",
36
+ "@cumulus/message": "9.4.1",
37
+ "@cumulus/types": "9.4.1",
38
38
  "is-valid-hostname": "0.0.1",
39
39
  "knex": "0.21.13",
40
40
  "lodash": "^4.17.20",
@@ -43,8 +43,7 @@
43
43
  "uuid": "8.3.1"
44
44
  },
45
45
  "devDependencies": {
46
- "@cumulus/message": "9.2.4",
47
46
  "@types/uuid": "^8.0.0"
48
47
  },
49
- "gitHead": "5e5890eaefaecdcb54c382dbb2300c794378c593"
48
+ "gitHead": "fce4415918c43a6a14d46ac7d9572f5a97a98a45"
50
49
  }