@cumulus/db 18.4.0 → 19.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/dist/index.d.ts +5 -0
- package/dist/index.js +11 -1
- package/dist/migrations/20240728101230_add_table_indexes.d.ts +4 -0
- package/dist/migrations/20240728101230_add_table_indexes.js +53 -0
- package/dist/models/execution.d.ts +2 -2
- package/dist/models/execution.js +1 -1
- package/dist/search/BaseSearch.d.ts +187 -0
- package/dist/search/BaseSearch.js +416 -0
- package/dist/search/CollectionSearch.d.ts +79 -0
- package/dist/search/CollectionSearch.js +162 -0
- package/dist/search/ExecutionSearch.d.ts +62 -0
- package/dist/search/ExecutionSearch.js +133 -0
- package/dist/search/GranuleSearch.d.ts +55 -0
- package/dist/search/GranuleSearch.js +109 -0
- package/dist/search/StatsSearch.d.ts +111 -0
- package/dist/search/StatsSearch.js +214 -0
- package/dist/search/field-mapping.d.ts +16 -0
- package/dist/search/field-mapping.js +304 -0
- package/dist/search/queries.d.ts +10 -0
- package/dist/search/queries.js +235 -0
- package/dist/translate/executions.d.ts +6 -0
- package/dist/translate/executions.js +32 -23
- package/dist/translate/granules.d.ts +24 -0
- package/dist/translate/granules.js +48 -27
- package/dist/types/search.d.ts +52 -0
- package/dist/types/search.js +3 -0
- package/package.json +8 -8
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Knex } from 'knex';
|
|
2
|
+
import { ApiExecutionRecord } from '@cumulus/types/api/executions';
|
|
3
|
+
import { BaseSearch } from './BaseSearch';
|
|
4
|
+
import { DbQueryParameters, QueryEvent } from '../types/search';
|
|
5
|
+
import { PostgresExecutionRecord } from '../types/execution';
|
|
6
|
+
import { BaseRecord } from '../types/base';
|
|
7
|
+
interface ExecutionRecord extends BaseRecord, PostgresExecutionRecord {
|
|
8
|
+
collectionName?: string;
|
|
9
|
+
collectionVersion?: string;
|
|
10
|
+
asyncOperationId?: string;
|
|
11
|
+
parentArn?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Class to build and execute db search query for executions
|
|
15
|
+
*/
|
|
16
|
+
export declare class ExecutionSearch extends BaseSearch {
|
|
17
|
+
constructor(event: QueryEvent);
|
|
18
|
+
/**
|
|
19
|
+
* check if joined async_ops table search is needed
|
|
20
|
+
*
|
|
21
|
+
* @returns whether collection search is needed
|
|
22
|
+
*/
|
|
23
|
+
protected searchAsync(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* check if joined async_ops table search is needed
|
|
26
|
+
*
|
|
27
|
+
* @returns whether collection search is needed
|
|
28
|
+
*/
|
|
29
|
+
protected searchParent(): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Build basic query
|
|
32
|
+
*
|
|
33
|
+
* @param knex - DB client
|
|
34
|
+
* @returns queries for getting count and search result
|
|
35
|
+
*/
|
|
36
|
+
protected buildBasicQuery(knex: Knex): {
|
|
37
|
+
countQuery: Knex.QueryBuilder;
|
|
38
|
+
searchQuery: Knex.QueryBuilder;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Build queries for infix and prefix
|
|
42
|
+
*
|
|
43
|
+
* @param params
|
|
44
|
+
* @param params.countQuery - query builder for getting count
|
|
45
|
+
* @param params.searchQuery - query builder for search
|
|
46
|
+
* @param [params.dbQueryParameters] - db query parameters
|
|
47
|
+
*/
|
|
48
|
+
protected buildInfixPrefixQuery(params: {
|
|
49
|
+
countQuery: Knex.QueryBuilder;
|
|
50
|
+
searchQuery: Knex.QueryBuilder;
|
|
51
|
+
dbQueryParameters?: DbQueryParameters;
|
|
52
|
+
}): void;
|
|
53
|
+
/**
|
|
54
|
+
* Translate postgres records to api records
|
|
55
|
+
*
|
|
56
|
+
* @param pgRecords - postgres records returned from query
|
|
57
|
+
* @returns translated api records
|
|
58
|
+
*/
|
|
59
|
+
protected translatePostgresRecordsToApiRecords(pgRecords: ExecutionRecord[]): Partial<ApiExecutionRecord>[];
|
|
60
|
+
}
|
|
61
|
+
export {};
|
|
62
|
+
//# sourceMappingURL=ExecutionSearch.d.ts.map
|
|
@@ -0,0 +1,133 @@
|
|
|
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.ExecutionSearch = void 0;
|
|
7
|
+
const logger_1 = __importDefault(require("@cumulus/logger"));
|
|
8
|
+
const pick_1 = __importDefault(require("lodash/pick"));
|
|
9
|
+
const set_1 = __importDefault(require("lodash/set"));
|
|
10
|
+
const Collections_1 = require("@cumulus/message/Collections");
|
|
11
|
+
const BaseSearch_1 = require("./BaseSearch");
|
|
12
|
+
const executions_1 = require("../translate/executions");
|
|
13
|
+
const tables_1 = require("../tables");
|
|
14
|
+
const log = new logger_1.default({ sender: '@cumulus/db/ExecutionSearch' });
|
|
15
|
+
/**
|
|
16
|
+
* Class to build and execute db search query for executions
|
|
17
|
+
*/
|
|
18
|
+
class ExecutionSearch extends BaseSearch_1.BaseSearch {
|
|
19
|
+
constructor(event) {
|
|
20
|
+
// estimate the table rowcount by default
|
|
21
|
+
if (event?.queryStringParameters?.estimateTableRowCount !== 'false') {
|
|
22
|
+
(0, set_1.default)(event, 'queryStringParameters.estimateTableRowCount', 'true');
|
|
23
|
+
}
|
|
24
|
+
super(event, 'execution');
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* check if joined async_ops table search is needed
|
|
28
|
+
*
|
|
29
|
+
* @returns whether collection search is needed
|
|
30
|
+
*/
|
|
31
|
+
searchAsync() {
|
|
32
|
+
const { not, term, terms } = this.dbQueryParameters;
|
|
33
|
+
return (!!(not?.asyncOperationId || term?.asyncOperationId || terms?.asyncOperationId));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* check if joined async_ops table search is needed
|
|
37
|
+
*
|
|
38
|
+
* @returns whether collection search is needed
|
|
39
|
+
*/
|
|
40
|
+
searchParent() {
|
|
41
|
+
const { not, term, terms } = this.dbQueryParameters;
|
|
42
|
+
return (!!(not?.parentArn || term?.parentArn || terms?.parentArn));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Build basic query
|
|
46
|
+
*
|
|
47
|
+
* @param knex - DB client
|
|
48
|
+
* @returns queries for getting count and search result
|
|
49
|
+
*/
|
|
50
|
+
buildBasicQuery(knex) {
|
|
51
|
+
const { collections: collectionsTable, asyncOperations: asyncOperationsTable, executions: executionsTable, } = tables_1.TableNames;
|
|
52
|
+
const searchQuery = knex(`${this.tableName}`)
|
|
53
|
+
.select(`${this.tableName}.*`)
|
|
54
|
+
.select({
|
|
55
|
+
collectionName: `${collectionsTable}.name`,
|
|
56
|
+
collectionVersion: `${collectionsTable}.version`,
|
|
57
|
+
});
|
|
58
|
+
if (this.searchAsync() || this.dbQueryParameters.includeFullRecord) {
|
|
59
|
+
searchQuery.select({ asyncOperationId: `${asyncOperationsTable}.id` });
|
|
60
|
+
}
|
|
61
|
+
if (this.searchParent() || this.dbQueryParameters.includeFullRecord) {
|
|
62
|
+
searchQuery.select({ parentArn: `${executionsTable}_parent.arn` });
|
|
63
|
+
}
|
|
64
|
+
const countQuery = knex(this.tableName)
|
|
65
|
+
.count('*');
|
|
66
|
+
if (this.searchCollection()) {
|
|
67
|
+
countQuery.innerJoin(collectionsTable, `${this.tableName}.collection_cumulus_id`, `${collectionsTable}.cumulus_id`);
|
|
68
|
+
searchQuery.innerJoin(collectionsTable, `${this.tableName}.collection_cumulus_id`, `${collectionsTable}.cumulus_id`);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
searchQuery.leftJoin(collectionsTable, `${this.tableName}.collection_cumulus_id`, `${collectionsTable}.cumulus_id`);
|
|
72
|
+
}
|
|
73
|
+
if (this.searchAsync()) {
|
|
74
|
+
countQuery.innerJoin(asyncOperationsTable, `${this.tableName}.async_operation_cumulus_id`, `${asyncOperationsTable}.cumulus_id`);
|
|
75
|
+
searchQuery.innerJoin(asyncOperationsTable, `${this.tableName}.async_operation_cumulus_id`, `${asyncOperationsTable}.cumulus_id`);
|
|
76
|
+
}
|
|
77
|
+
else if (this.dbQueryParameters.includeFullRecord) {
|
|
78
|
+
searchQuery.leftJoin(asyncOperationsTable, `${this.tableName}.async_operation_cumulus_id`, `${asyncOperationsTable}.cumulus_id`);
|
|
79
|
+
}
|
|
80
|
+
if (this.searchParent()) {
|
|
81
|
+
countQuery.innerJoin(`${this.tableName} as ${this.tableName}_parent`, `${this.tableName}.parent_cumulus_id`, `${this.tableName}_parent.cumulus_id`);
|
|
82
|
+
searchQuery.innerJoin(`${this.tableName} as ${this.tableName}_parent`, `${this.tableName}.parent_cumulus_id`, `${this.tableName}_parent.cumulus_id`);
|
|
83
|
+
}
|
|
84
|
+
else if (this.dbQueryParameters.includeFullRecord) {
|
|
85
|
+
searchQuery.leftJoin(`${this.tableName} as ${this.tableName}_parent`, `${this.tableName}.parent_cumulus_id`, `${this.tableName}_parent.cumulus_id`);
|
|
86
|
+
}
|
|
87
|
+
return { countQuery, searchQuery };
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Build queries for infix and prefix
|
|
91
|
+
*
|
|
92
|
+
* @param params
|
|
93
|
+
* @param params.countQuery - query builder for getting count
|
|
94
|
+
* @param params.searchQuery - query builder for search
|
|
95
|
+
* @param [params.dbQueryParameters] - db query parameters
|
|
96
|
+
*/
|
|
97
|
+
buildInfixPrefixQuery(params) {
|
|
98
|
+
const { countQuery, searchQuery, dbQueryParameters } = params;
|
|
99
|
+
const { infix, prefix } = dbQueryParameters ?? this.dbQueryParameters;
|
|
100
|
+
if (infix) {
|
|
101
|
+
[countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.arn`, `%${infix}%`));
|
|
102
|
+
}
|
|
103
|
+
if (prefix) {
|
|
104
|
+
[countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.arn`, `%${prefix}%`));
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Translate postgres records to api records
|
|
109
|
+
*
|
|
110
|
+
* @param pgRecords - postgres records returned from query
|
|
111
|
+
* @returns translated api records
|
|
112
|
+
*/
|
|
113
|
+
translatePostgresRecordsToApiRecords(pgRecords) {
|
|
114
|
+
log.debug(`translatePostgresRecordsToApiRecords number of records ${pgRecords.length} `);
|
|
115
|
+
const apiRecords = pgRecords.map((executionRecord) => {
|
|
116
|
+
const { collectionName, collectionVersion, asyncOperationId, parentArn } = executionRecord;
|
|
117
|
+
const collectionId = collectionName && collectionVersion
|
|
118
|
+
? (0, Collections_1.constructCollectionId)(collectionName, collectionVersion) : undefined;
|
|
119
|
+
const apiRecord = (0, executions_1.translatePostgresExecutionToApiExecutionWithoutDbQuery)({
|
|
120
|
+
executionRecord,
|
|
121
|
+
collectionId,
|
|
122
|
+
asyncOperationId,
|
|
123
|
+
parentArn,
|
|
124
|
+
});
|
|
125
|
+
return this.dbQueryParameters.fields
|
|
126
|
+
? (0, pick_1.default)(apiRecord, this.dbQueryParameters.fields)
|
|
127
|
+
: apiRecord;
|
|
128
|
+
});
|
|
129
|
+
return apiRecords;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.ExecutionSearch = ExecutionSearch;
|
|
133
|
+
//# sourceMappingURL=ExecutionSearch.js.map
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Knex } from 'knex';
|
|
2
|
+
import { ApiGranuleRecord } from '@cumulus/types/api/granules';
|
|
3
|
+
import { BaseRecord } from '../types/base';
|
|
4
|
+
import { BaseSearch } from './BaseSearch';
|
|
5
|
+
import { DbQueryParameters, QueryEvent } from '../types/search';
|
|
6
|
+
import { PostgresGranuleRecord } from '../types/granule';
|
|
7
|
+
interface GranuleRecord extends BaseRecord, PostgresGranuleRecord {
|
|
8
|
+
cumulus_id: number;
|
|
9
|
+
updated_at: Date;
|
|
10
|
+
collection_cumulus_id: number;
|
|
11
|
+
collectionName: string;
|
|
12
|
+
collectionVersion: string;
|
|
13
|
+
pdr_cumulus_id: number;
|
|
14
|
+
pdrName?: string;
|
|
15
|
+
provider_cumulus_id?: number;
|
|
16
|
+
providerName?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Class to build and execute db search query for granules
|
|
20
|
+
*/
|
|
21
|
+
export declare class GranuleSearch extends BaseSearch {
|
|
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
|
+
/**
|
|
34
|
+
* Build queries for infix and prefix
|
|
35
|
+
*
|
|
36
|
+
* @param params
|
|
37
|
+
* @param params.countQuery - query builder for getting count
|
|
38
|
+
* @param params.searchQuery - query builder for search
|
|
39
|
+
* @param [params.dbQueryParameters] - db query parameters
|
|
40
|
+
*/
|
|
41
|
+
protected buildInfixPrefixQuery(params: {
|
|
42
|
+
countQuery: Knex.QueryBuilder;
|
|
43
|
+
searchQuery: Knex.QueryBuilder;
|
|
44
|
+
dbQueryParameters?: DbQueryParameters;
|
|
45
|
+
}): void;
|
|
46
|
+
/**
|
|
47
|
+
* Translate postgres records to api records
|
|
48
|
+
*
|
|
49
|
+
* @param pgRecords - postgres records returned from query
|
|
50
|
+
* @returns translated api records
|
|
51
|
+
*/
|
|
52
|
+
protected translatePostgresRecordsToApiRecords(pgRecords: GranuleRecord[]): Partial<ApiGranuleRecord>[];
|
|
53
|
+
}
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=GranuleSearch.d.ts.map
|
|
@@ -0,0 +1,109 @@
|
|
|
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.GranuleSearch = void 0;
|
|
7
|
+
const pick_1 = __importDefault(require("lodash/pick"));
|
|
8
|
+
const set_1 = __importDefault(require("lodash/set"));
|
|
9
|
+
const logger_1 = __importDefault(require("@cumulus/logger"));
|
|
10
|
+
const BaseSearch_1 = require("./BaseSearch");
|
|
11
|
+
const granules_1 = require("../translate/granules");
|
|
12
|
+
const tables_1 = require("../tables");
|
|
13
|
+
const log = new logger_1.default({ sender: '@cumulus/db/GranuleSearch' });
|
|
14
|
+
/**
|
|
15
|
+
* Class to build and execute db search query for granules
|
|
16
|
+
*/
|
|
17
|
+
class GranuleSearch extends BaseSearch_1.BaseSearch {
|
|
18
|
+
constructor(event) {
|
|
19
|
+
// estimate the table rowcount by default
|
|
20
|
+
if (event?.queryStringParameters?.estimateTableRowCount !== 'false') {
|
|
21
|
+
(0, set_1.default)(event, 'queryStringParameters.estimateTableRowCount', 'true');
|
|
22
|
+
}
|
|
23
|
+
super(event, 'granule');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build basic query
|
|
27
|
+
*
|
|
28
|
+
* @param knex - DB client
|
|
29
|
+
* @returns queries for getting count and search result
|
|
30
|
+
*/
|
|
31
|
+
buildBasicQuery(knex) {
|
|
32
|
+
const { collections: collectionsTable, providers: providersTable, pdrs: pdrsTable, } = tables_1.TableNames;
|
|
33
|
+
const countQuery = knex(this.tableName)
|
|
34
|
+
.count('*');
|
|
35
|
+
const searchQuery = knex(this.tableName)
|
|
36
|
+
.select(`${this.tableName}.*`)
|
|
37
|
+
.select({
|
|
38
|
+
providerName: `${providersTable}.name`,
|
|
39
|
+
collectionName: `${collectionsTable}.name`,
|
|
40
|
+
collectionVersion: `${collectionsTable}.version`,
|
|
41
|
+
pdrName: `${pdrsTable}.name`,
|
|
42
|
+
})
|
|
43
|
+
.innerJoin(collectionsTable, `${this.tableName}.collection_cumulus_id`, `${collectionsTable}.cumulus_id`);
|
|
44
|
+
if (this.searchCollection()) {
|
|
45
|
+
countQuery.innerJoin(collectionsTable, `${this.tableName}.collection_cumulus_id`, `${collectionsTable}.cumulus_id`);
|
|
46
|
+
}
|
|
47
|
+
if (this.searchProvider()) {
|
|
48
|
+
countQuery.innerJoin(providersTable, `${this.tableName}.provider_cumulus_id`, `${providersTable}.cumulus_id`);
|
|
49
|
+
searchQuery.innerJoin(providersTable, `${this.tableName}.provider_cumulus_id`, `${providersTable}.cumulus_id`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
searchQuery.leftJoin(providersTable, `${this.tableName}.provider_cumulus_id`, `${providersTable}.cumulus_id`);
|
|
53
|
+
}
|
|
54
|
+
if (this.searchPdr()) {
|
|
55
|
+
countQuery.innerJoin(pdrsTable, `${this.tableName}.pdr_cumulus_id`, `${pdrsTable}.cumulus_id`);
|
|
56
|
+
searchQuery.innerJoin(pdrsTable, `${this.tableName}.pdr_cumulus_id`, `${pdrsTable}.cumulus_id`);
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
searchQuery.leftJoin(pdrsTable, `${this.tableName}.pdr_cumulus_id`, `${pdrsTable}.cumulus_id`);
|
|
60
|
+
}
|
|
61
|
+
return { countQuery, searchQuery };
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Build queries for infix and prefix
|
|
65
|
+
*
|
|
66
|
+
* @param params
|
|
67
|
+
* @param params.countQuery - query builder for getting count
|
|
68
|
+
* @param params.searchQuery - query builder for search
|
|
69
|
+
* @param [params.dbQueryParameters] - db query parameters
|
|
70
|
+
*/
|
|
71
|
+
buildInfixPrefixQuery(params) {
|
|
72
|
+
const { countQuery, searchQuery, dbQueryParameters } = params;
|
|
73
|
+
const { infix, prefix } = dbQueryParameters ?? this.dbQueryParameters;
|
|
74
|
+
if (infix) {
|
|
75
|
+
[countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.granule_id`, `%${infix}%`));
|
|
76
|
+
}
|
|
77
|
+
if (prefix) {
|
|
78
|
+
[countQuery, searchQuery].forEach((query) => query.whereLike(`${this.tableName}.granule_id`, `${prefix}%`));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Translate postgres records to api records
|
|
83
|
+
*
|
|
84
|
+
* @param pgRecords - postgres records returned from query
|
|
85
|
+
* @returns translated api records
|
|
86
|
+
*/
|
|
87
|
+
translatePostgresRecordsToApiRecords(pgRecords) {
|
|
88
|
+
log.debug(`translatePostgresRecordsToApiRecords number of records ${pgRecords.length} `);
|
|
89
|
+
const apiRecords = pgRecords.map((item) => {
|
|
90
|
+
const granulePgRecord = item;
|
|
91
|
+
const collectionPgRecord = {
|
|
92
|
+
cumulus_id: item.collection_cumulus_id,
|
|
93
|
+
name: item.collectionName,
|
|
94
|
+
version: item.collectionVersion,
|
|
95
|
+
};
|
|
96
|
+
const pdr = item.pdrName ? { name: item.pdrName } : undefined;
|
|
97
|
+
const providerPgRecord = item.providerName ? { name: item.providerName } : undefined;
|
|
98
|
+
const apiRecord = (0, granules_1.translatePostgresGranuleToApiGranuleWithoutDbQuery)({
|
|
99
|
+
granulePgRecord, collectionPgRecord, pdr, providerPgRecord,
|
|
100
|
+
});
|
|
101
|
+
return this.dbQueryParameters.fields
|
|
102
|
+
? (0, pick_1.default)(apiRecord, this.dbQueryParameters.fields)
|
|
103
|
+
: apiRecord;
|
|
104
|
+
});
|
|
105
|
+
return apiRecords;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.GranuleSearch = GranuleSearch;
|
|
109
|
+
//# sourceMappingURL=GranuleSearch.js.map
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Knex } from 'knex';
|
|
2
|
+
import { DbQueryParameters, QueryEvent } from '../types/search';
|
|
3
|
+
import { BaseSearch } from './BaseSearch';
|
|
4
|
+
declare type Summary = {
|
|
5
|
+
dateFrom: string;
|
|
6
|
+
dateTo: string;
|
|
7
|
+
value: number;
|
|
8
|
+
aggregation: string;
|
|
9
|
+
unit: string;
|
|
10
|
+
};
|
|
11
|
+
declare type SummaryResult = {
|
|
12
|
+
errors: Summary;
|
|
13
|
+
granules: Summary;
|
|
14
|
+
collections: Summary;
|
|
15
|
+
processingTime: Summary;
|
|
16
|
+
};
|
|
17
|
+
declare type Meta = {
|
|
18
|
+
name: string;
|
|
19
|
+
count: number;
|
|
20
|
+
field: string;
|
|
21
|
+
};
|
|
22
|
+
declare type AggregateRes = {
|
|
23
|
+
key: string;
|
|
24
|
+
count: number;
|
|
25
|
+
};
|
|
26
|
+
declare type ApiAggregateResult = {
|
|
27
|
+
meta: Meta;
|
|
28
|
+
count: AggregateRes[];
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* A class to query postgres for the STATS and STATS/AGGREGATE endpoints
|
|
32
|
+
*/
|
|
33
|
+
declare class StatsSearch extends BaseSearch {
|
|
34
|
+
readonly field: string;
|
|
35
|
+
constructor(event: QueryEvent, type: string);
|
|
36
|
+
/**
|
|
37
|
+
* Formats the postgres records into an API stats/aggregate response
|
|
38
|
+
*
|
|
39
|
+
* @param result - the postgres query results
|
|
40
|
+
* @returns the api object with the aggregate statistics
|
|
41
|
+
*/
|
|
42
|
+
private formatAggregateResult;
|
|
43
|
+
/**
|
|
44
|
+
* Formats the postgres results into an API stats/summary response
|
|
45
|
+
*
|
|
46
|
+
* @param result - the knex summary query results
|
|
47
|
+
* @returns the api object with the summary statistics
|
|
48
|
+
*/
|
|
49
|
+
private formatSummaryResult;
|
|
50
|
+
/**
|
|
51
|
+
* Queries postgres for a summary of statistics around the granules in the system
|
|
52
|
+
*
|
|
53
|
+
* @param testKnex - the knex client to be used
|
|
54
|
+
* @returns the postgres aggregations based on query
|
|
55
|
+
*/
|
|
56
|
+
summary(testKnex?: Knex): Promise<SummaryResult>;
|
|
57
|
+
/**
|
|
58
|
+
* Performs joins on the collections/pdrs/providers table if neccessary
|
|
59
|
+
*
|
|
60
|
+
* @param query - the knex query to be joined or not
|
|
61
|
+
*/
|
|
62
|
+
private joinTables;
|
|
63
|
+
/**
|
|
64
|
+
* Aggregates the search query based on queryStringParameters
|
|
65
|
+
*
|
|
66
|
+
* @param query - the knex query to be aggregated
|
|
67
|
+
* @param knex - the knex client to be used
|
|
68
|
+
*/
|
|
69
|
+
private aggregateQueryField;
|
|
70
|
+
/**
|
|
71
|
+
* Builds basic query
|
|
72
|
+
*
|
|
73
|
+
* @param knex - the knex client
|
|
74
|
+
* @returns the search query
|
|
75
|
+
*/
|
|
76
|
+
protected buildBasicQuery(knex: Knex): {
|
|
77
|
+
searchQuery: Knex.QueryBuilder;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* Builds queries for infix and prefix
|
|
81
|
+
*
|
|
82
|
+
* @param params
|
|
83
|
+
* @param params.searchQuery - the search query
|
|
84
|
+
* @param [params.dbQueryParameters] - the db query parameters
|
|
85
|
+
*/
|
|
86
|
+
protected buildInfixPrefixQuery(params: {
|
|
87
|
+
searchQuery: Knex.QueryBuilder;
|
|
88
|
+
dbQueryParameters?: DbQueryParameters;
|
|
89
|
+
}): void;
|
|
90
|
+
/**
|
|
91
|
+
* Builds queries for term fields
|
|
92
|
+
*
|
|
93
|
+
* @param params
|
|
94
|
+
* @param params.searchQuery - the search query
|
|
95
|
+
* @param [params.dbQueryParameters] - the db query parameters
|
|
96
|
+
* @returns the updated search query based on queryStringParams
|
|
97
|
+
*/
|
|
98
|
+
protected buildTermQuery(params: {
|
|
99
|
+
searchQuery: Knex.QueryBuilder;
|
|
100
|
+
dbQueryParameters?: DbQueryParameters;
|
|
101
|
+
}): void;
|
|
102
|
+
/**
|
|
103
|
+
* Executes the aggregate search query
|
|
104
|
+
*
|
|
105
|
+
* @param testKnex - the knex client to be used
|
|
106
|
+
* @returns the aggregate query results in api format
|
|
107
|
+
*/
|
|
108
|
+
aggregate(testKnex?: Knex): Promise<ApiAggregateResult>;
|
|
109
|
+
}
|
|
110
|
+
export { StatsSearch };
|
|
111
|
+
//# sourceMappingURL=StatsSearch.d.ts.map
|
|
@@ -0,0 +1,214 @@
|
|
|
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.StatsSearch = void 0;
|
|
7
|
+
const omit_1 = __importDefault(require("lodash/omit"));
|
|
8
|
+
const logger_1 = __importDefault(require("@cumulus/logger"));
|
|
9
|
+
const connection_1 = require("../connection");
|
|
10
|
+
const tables_1 = require("../tables");
|
|
11
|
+
const BaseSearch_1 = require("./BaseSearch");
|
|
12
|
+
const log = new logger_1.default({ sender: '@cumulus/db/StatsSearch' });
|
|
13
|
+
const infixMapping = {
|
|
14
|
+
granules: 'granule_id',
|
|
15
|
+
collections: 'name',
|
|
16
|
+
providers: 'name',
|
|
17
|
+
executions: 'arn',
|
|
18
|
+
pdrs: 'name',
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A class to query postgres for the STATS and STATS/AGGREGATE endpoints
|
|
22
|
+
*/
|
|
23
|
+
class StatsSearch extends BaseSearch_1.BaseSearch {
|
|
24
|
+
constructor(event, type) {
|
|
25
|
+
const { field, ...queryStringParameters } = event.queryStringParameters || {};
|
|
26
|
+
super({ queryStringParameters }, type);
|
|
27
|
+
this.field = field ?? 'status';
|
|
28
|
+
this.dbQueryParameters = (0, omit_1.default)(this.dbQueryParameters, ['limit', 'offset']);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Formats the postgres records into an API stats/aggregate response
|
|
32
|
+
*
|
|
33
|
+
* @param result - the postgres query results
|
|
34
|
+
* @returns the api object with the aggregate statistics
|
|
35
|
+
*/
|
|
36
|
+
formatAggregateResult(result) {
|
|
37
|
+
let totalCount = 0;
|
|
38
|
+
const responses = [];
|
|
39
|
+
for (const row of Object.keys(result)) {
|
|
40
|
+
responses.push({
|
|
41
|
+
key: result[row].aggregatedfield,
|
|
42
|
+
count: Number.parseInt(result[row].count, 10),
|
|
43
|
+
});
|
|
44
|
+
totalCount += Number(result[row].count);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
meta: {
|
|
48
|
+
name: 'cumulus-api',
|
|
49
|
+
count: totalCount,
|
|
50
|
+
field: this.field,
|
|
51
|
+
},
|
|
52
|
+
count: responses,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Formats the postgres results into an API stats/summary response
|
|
57
|
+
*
|
|
58
|
+
* @param result - the knex summary query results
|
|
59
|
+
* @returns the api object with the summary statistics
|
|
60
|
+
*/
|
|
61
|
+
formatSummaryResult(result) {
|
|
62
|
+
const timestampTo = this.dbQueryParameters.range?.updated_at?.lte ?? new Date();
|
|
63
|
+
const timestampFrom = this.dbQueryParameters.range?.updated_at?.gte ?? new Date(0);
|
|
64
|
+
const dateto = timestampTo.toISOString();
|
|
65
|
+
const datefrom = timestampFrom.toISOString();
|
|
66
|
+
return {
|
|
67
|
+
errors: {
|
|
68
|
+
dateFrom: datefrom,
|
|
69
|
+
dateTo: dateto,
|
|
70
|
+
value: Number(result.count_errors),
|
|
71
|
+
aggregation: 'count',
|
|
72
|
+
unit: 'error',
|
|
73
|
+
},
|
|
74
|
+
collections: {
|
|
75
|
+
dateFrom: datefrom,
|
|
76
|
+
dateTo: dateto,
|
|
77
|
+
value: Number(result.count_collections),
|
|
78
|
+
aggregation: 'count',
|
|
79
|
+
unit: 'collection',
|
|
80
|
+
},
|
|
81
|
+
processingTime: {
|
|
82
|
+
dateFrom: datefrom,
|
|
83
|
+
dateTo: dateto,
|
|
84
|
+
value: Number(result.avg_processing_time),
|
|
85
|
+
aggregation: 'average',
|
|
86
|
+
unit: 'second',
|
|
87
|
+
},
|
|
88
|
+
granules: {
|
|
89
|
+
dateFrom: datefrom,
|
|
90
|
+
dateTo: dateto,
|
|
91
|
+
value: Number(result.count_granules),
|
|
92
|
+
aggregation: 'count',
|
|
93
|
+
unit: 'granule',
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Queries postgres for a summary of statistics around the granules in the system
|
|
99
|
+
*
|
|
100
|
+
* @param testKnex - the knex client to be used
|
|
101
|
+
* @returns the postgres aggregations based on query
|
|
102
|
+
*/
|
|
103
|
+
async summary(testKnex) {
|
|
104
|
+
const knex = testKnex ?? await (0, connection_1.getKnexClient)();
|
|
105
|
+
const aggregateQuery = knex(this.tableName);
|
|
106
|
+
this.buildRangeQuery({ searchQuery: aggregateQuery });
|
|
107
|
+
aggregateQuery.select(knex.raw(`COUNT(CASE WHEN ${this.tableName}.error ->> 'Error' is not null THEN 1 END) AS count_errors`), knex.raw('COUNT(*) AS count_granules'), knex.raw(`AVG(${this.tableName}.duration) AS avg_processing_time`), knex.raw(`COUNT(DISTINCT ${this.tableName}.collection_cumulus_id) AS count_collections`));
|
|
108
|
+
log.debug(`summary about to execute query: ${aggregateQuery?.toSQL().sql}`);
|
|
109
|
+
const aggregateQueryRes = await aggregateQuery;
|
|
110
|
+
return this.formatSummaryResult(aggregateQueryRes[0]);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Performs joins on the collections/pdrs/providers table if neccessary
|
|
114
|
+
*
|
|
115
|
+
* @param query - the knex query to be joined or not
|
|
116
|
+
*/
|
|
117
|
+
joinTables(query) {
|
|
118
|
+
const { collections: collectionsTable, providers: providersTable, pdrs: pdrsTable, } = tables_1.TableNames;
|
|
119
|
+
if (this.searchCollection()) {
|
|
120
|
+
query.join(collectionsTable, `${this.tableName}.collection_cumulus_id`, `${collectionsTable}.cumulus_id`);
|
|
121
|
+
}
|
|
122
|
+
if (this.searchProvider()) {
|
|
123
|
+
query.join(providersTable, `${this.tableName}.provider_cumulus_id`, `${providersTable}.cumulus_id`);
|
|
124
|
+
}
|
|
125
|
+
if (this.searchPdr()) {
|
|
126
|
+
query.join(pdrsTable, `${this.tableName}.pdr_cumulus_id`, `${pdrsTable}.cumulus_id`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Aggregates the search query based on queryStringParameters
|
|
131
|
+
*
|
|
132
|
+
* @param query - the knex query to be aggregated
|
|
133
|
+
* @param knex - the knex client to be used
|
|
134
|
+
*/
|
|
135
|
+
aggregateQueryField(query, knex) {
|
|
136
|
+
if (this.field?.includes('error.Error')) {
|
|
137
|
+
query.select(knex.raw("error ->> 'Error' as aggregatedfield"));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
query.select(`${this.tableName}.${this.field} as aggregatedfield`);
|
|
141
|
+
}
|
|
142
|
+
query.modify((queryBuilder) => this.joinTables(queryBuilder))
|
|
143
|
+
.count('* as count')
|
|
144
|
+
.groupBy('aggregatedfield')
|
|
145
|
+
.orderBy([{ column: 'count', order: 'desc' }, { column: 'aggregatedfield' }]);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Builds basic query
|
|
149
|
+
*
|
|
150
|
+
* @param knex - the knex client
|
|
151
|
+
* @returns the search query
|
|
152
|
+
*/
|
|
153
|
+
buildBasicQuery(knex) {
|
|
154
|
+
const searchQuery = knex(this.tableName);
|
|
155
|
+
this.aggregateQueryField(searchQuery, knex);
|
|
156
|
+
return { searchQuery };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Builds queries for infix and prefix
|
|
160
|
+
*
|
|
161
|
+
* @param params
|
|
162
|
+
* @param params.searchQuery - the search query
|
|
163
|
+
* @param [params.dbQueryParameters] - the db query parameters
|
|
164
|
+
*/
|
|
165
|
+
buildInfixPrefixQuery(params) {
|
|
166
|
+
const { searchQuery, dbQueryParameters } = params;
|
|
167
|
+
const { infix, prefix } = dbQueryParameters || this.dbQueryParameters;
|
|
168
|
+
const fieldName = infixMapping[this.tableName];
|
|
169
|
+
if (infix) {
|
|
170
|
+
searchQuery.whereLike(`${this.tableName}.${fieldName}`, `%${infix}%`);
|
|
171
|
+
}
|
|
172
|
+
if (prefix) {
|
|
173
|
+
searchQuery.whereLike(`${this.tableName}.${fieldName}`, `%${prefix}%`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Builds queries for term fields
|
|
178
|
+
*
|
|
179
|
+
* @param params
|
|
180
|
+
* @param params.searchQuery - the search query
|
|
181
|
+
* @param [params.dbQueryParameters] - the db query parameters
|
|
182
|
+
* @returns the updated search query based on queryStringParams
|
|
183
|
+
*/
|
|
184
|
+
buildTermQuery(params) {
|
|
185
|
+
const { dbQueryParameters, searchQuery } = params;
|
|
186
|
+
const { term = {} } = dbQueryParameters ?? this.dbQueryParameters;
|
|
187
|
+
if (this.field?.includes('error.Error')) {
|
|
188
|
+
searchQuery.whereRaw(`${this.tableName}.error ->> 'Error' is not null`);
|
|
189
|
+
}
|
|
190
|
+
return super.buildTermQuery({
|
|
191
|
+
...params,
|
|
192
|
+
dbQueryParameters: { term: (0, omit_1.default)(term, 'error.Error') },
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Executes the aggregate search query
|
|
197
|
+
*
|
|
198
|
+
* @param testKnex - the knex client to be used
|
|
199
|
+
* @returns the aggregate query results in api format
|
|
200
|
+
*/
|
|
201
|
+
async aggregate(testKnex) {
|
|
202
|
+
const knex = testKnex ?? await (0, connection_1.getKnexClient)();
|
|
203
|
+
const { searchQuery } = this.buildSearch(knex);
|
|
204
|
+
try {
|
|
205
|
+
const pgRecords = await searchQuery;
|
|
206
|
+
return this.formatAggregateResult(pgRecords);
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
return error;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
exports.StatsSearch = StatsSearch;
|
|
214
|
+
//# sourceMappingURL=StatsSearch.js.map
|