@cubejs-backend/query-orchestrator 0.30.43 → 0.30.47
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/CHANGELOG.md +36 -0
- package/dist/src/driver/driver.interface.d.ts +12 -2
- package/dist/src/driver/driver.interface.d.ts.map +1 -1
- package/dist/src/orchestrator/PreAggregations.d.ts +40 -7
- package/dist/src/orchestrator/PreAggregations.d.ts.map +1 -1
- package/dist/src/orchestrator/PreAggregations.js +131 -52
- package/dist/src/orchestrator/PreAggregations.js.map +1 -1
- package/dist/src/orchestrator/QueryCache.d.ts +7 -2
- package/dist/src/orchestrator/QueryCache.d.ts.map +1 -1
- package/dist/src/orchestrator/QueryCache.js +57 -9
- package/dist/src/orchestrator/QueryCache.js.map +1 -1
- package/dist/src/orchestrator/QueryOrchestrator.d.ts.map +1 -1
- package/dist/src/orchestrator/QueryOrchestrator.js +5 -1
- package/dist/src/orchestrator/QueryOrchestrator.js.map +1 -1
- package/dist/src/orchestrator/QueryQueue.js +1 -1
- package/package.json +6 -4
|
@@ -3,7 +3,7 @@ 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.PreAggregations = exports.PreAggregationPartitionRangeLoader = exports.PreAggregationLoader = exports.getLastUpdatedAtTimestamp = void 0;
|
|
6
|
+
exports.PreAggregations = exports.PreAggregationPartitionRangeLoader = exports.PreAggregationLoader = exports.getLastUpdatedAtTimestamp = exports.LAMBDA_TABLE_PREFIX = void 0;
|
|
7
7
|
const crypto_1 = __importDefault(require("crypto"));
|
|
8
8
|
const ramda_1 = __importDefault(require("ramda"));
|
|
9
9
|
const shared_1 = require("@cubejs-backend/shared");
|
|
@@ -13,6 +13,8 @@ const LocalCacheDriver_1 = require("./LocalCacheDriver");
|
|
|
13
13
|
const QueryCache_1 = require("./QueryCache");
|
|
14
14
|
const ContinueWaitError_1 = require("./ContinueWaitError");
|
|
15
15
|
const StreamObjectsCounter_1 = require("./StreamObjectsCounter");
|
|
16
|
+
/// Name of the inline table containing the lambda rows.
|
|
17
|
+
exports.LAMBDA_TABLE_PREFIX = 'lambda';
|
|
16
18
|
function encodeTimeStamp(time) {
|
|
17
19
|
return Math.floor(time / 1000).toString(32);
|
|
18
20
|
}
|
|
@@ -71,7 +73,8 @@ const tablesToVersionEntries = (schema, tables) => ramda_1.default.sortBy(table
|
|
|
71
73
|
const entity = {
|
|
72
74
|
table_name: `${schema}.${match[1]}`,
|
|
73
75
|
content_version: match[2],
|
|
74
|
-
structure_version: match[3]
|
|
76
|
+
structure_version: match[3],
|
|
77
|
+
build_range_end: table.build_range_end,
|
|
75
78
|
};
|
|
76
79
|
if (match[4].length < 13) {
|
|
77
80
|
entity.last_updated_at = decodeTimeStamp(match[4]);
|
|
@@ -129,9 +132,13 @@ class PreAggregationLoadCache {
|
|
|
129
132
|
async getTablesQuery(preAggregation) {
|
|
130
133
|
const redisKey = this.tablesRedisKey(preAggregation);
|
|
131
134
|
if (!this.tables[redisKey]) {
|
|
132
|
-
|
|
135
|
+
const tables = this.preAggregations.options.skipExternalCacheAndQueue && preAggregation.external ?
|
|
133
136
|
await this.fetchTablesNoCache(preAggregation) :
|
|
134
137
|
await this.tablesFromCache(preAggregation);
|
|
138
|
+
if (tables === undefined) {
|
|
139
|
+
throw new Error('Pre-aggregation tables are undefined.');
|
|
140
|
+
}
|
|
141
|
+
this.tables[redisKey] = tables;
|
|
135
142
|
}
|
|
136
143
|
return this.tables[redisKey];
|
|
137
144
|
}
|
|
@@ -300,7 +307,8 @@ class PreAggregationLoader {
|
|
|
300
307
|
return {
|
|
301
308
|
targetTableName: this.targetTableName(versionEntryByStructureVersion),
|
|
302
309
|
refreshKeyValues: [],
|
|
303
|
-
lastUpdatedAt: versionEntryByStructureVersion.last_updated_at
|
|
310
|
+
lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
|
|
311
|
+
buildRangeEnd: versionEntryByStructureVersion.build_range_end,
|
|
304
312
|
};
|
|
305
313
|
}
|
|
306
314
|
else {
|
|
@@ -329,7 +337,8 @@ class PreAggregationLoader {
|
|
|
329
337
|
return {
|
|
330
338
|
targetTableName: this.targetTableName(versionEntryByContentVersion),
|
|
331
339
|
refreshKeyValues: [],
|
|
332
|
-
lastUpdatedAt: versionEntryByContentVersion.last_updated_at
|
|
340
|
+
lastUpdatedAt: versionEntryByContentVersion.last_updated_at,
|
|
341
|
+
buildRangeEnd: versionEntryByContentVersion.build_range_end,
|
|
333
342
|
};
|
|
334
343
|
}
|
|
335
344
|
// TODO this check can be redundant due to structure version is already checked in loadPreAggregation()
|
|
@@ -341,7 +350,8 @@ class PreAggregationLoader {
|
|
|
341
350
|
return {
|
|
342
351
|
targetTableName: this.targetTableName(versionEntryByStructureVersion),
|
|
343
352
|
refreshKeyValues: [],
|
|
344
|
-
lastUpdatedAt: versionEntryByStructureVersion.last_updated_at
|
|
353
|
+
lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
|
|
354
|
+
buildRangeEnd: versionEntryByStructureVersion.build_range_end,
|
|
345
355
|
};
|
|
346
356
|
}
|
|
347
357
|
}
|
|
@@ -370,7 +380,8 @@ class PreAggregationLoader {
|
|
|
370
380
|
return {
|
|
371
381
|
targetTableName: this.targetTableName(lastVersion),
|
|
372
382
|
refreshKeyValues: [],
|
|
373
|
-
lastUpdatedAt: lastVersion.last_updated_at
|
|
383
|
+
lastUpdatedAt: lastVersion.last_updated_at,
|
|
384
|
+
buildRangeEnd: lastVersion.build_range_end,
|
|
374
385
|
};
|
|
375
386
|
};
|
|
376
387
|
if (this.forceBuild) {
|
|
@@ -424,7 +435,8 @@ class PreAggregationLoader {
|
|
|
424
435
|
return {
|
|
425
436
|
targetTableName: this.targetTableName(versionEntry),
|
|
426
437
|
refreshKeyValues: [],
|
|
427
|
-
lastUpdatedAt: versionEntry.last_updated_at
|
|
438
|
+
lastUpdatedAt: versionEntry.last_updated_at,
|
|
439
|
+
buildRangeEnd: versionEntry.build_range_end,
|
|
428
440
|
};
|
|
429
441
|
}
|
|
430
442
|
contentVersion(invalidationKeys) {
|
|
@@ -464,7 +476,7 @@ class PreAggregationLoader {
|
|
|
464
476
|
invalidationKeys,
|
|
465
477
|
forceBuild: this.forceBuild,
|
|
466
478
|
metadata: this.metadata,
|
|
467
|
-
orphanedTimeout: this.orphanedTimeout
|
|
479
|
+
orphanedTimeout: this.orphanedTimeout,
|
|
468
480
|
}, priority,
|
|
469
481
|
// eslint-disable-next-line no-use-before-define
|
|
470
482
|
{ stageQueryKey: PreAggregations.preAggregationQueryCacheKey(this.preAggregation), requestId: this.requestId });
|
|
@@ -478,18 +490,16 @@ class PreAggregationLoader {
|
|
|
478
490
|
// eslint-disable-next-line no-use-before-define
|
|
479
491
|
return PreAggregations.targetTableName(versionEntry);
|
|
480
492
|
}
|
|
481
|
-
refresh(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
return utils_1.cancelCombinator(saveCancelFn => refreshStrategy.bind(this)(client, newVersionEntry, saveCancelFn, preAggregation, invalidationKeys));
|
|
492
|
-
};
|
|
493
|
+
refresh(newVersionEntry, invalidationKeys, client) {
|
|
494
|
+
let refreshStrategy = this.refreshImplStoreInSourceStrategy;
|
|
495
|
+
if (this.preAggregation.external) {
|
|
496
|
+
const readOnly = this.preAggregation.readOnly ||
|
|
497
|
+
client.config && client.config.readOnly ||
|
|
498
|
+
client.readOnly && (typeof client.readOnly === 'boolean' ? client.readOnly : client.readOnly());
|
|
499
|
+
refreshStrategy = readOnly ?
|
|
500
|
+
this.refreshImplStreamExternalStrategy : this.refreshImplTempTableExternalStrategy;
|
|
501
|
+
}
|
|
502
|
+
return utils_1.cancelCombinator(saveCancelFn => refreshStrategy.bind(this)(client, newVersionEntry, saveCancelFn, invalidationKeys));
|
|
493
503
|
}
|
|
494
504
|
logExecutingSql(payload) {
|
|
495
505
|
this.logger('Executing Load Pre Aggregation SQL', payload);
|
|
@@ -502,9 +512,10 @@ class PreAggregationLoader {
|
|
|
502
512
|
targetTableName,
|
|
503
513
|
requestId: this.requestId,
|
|
504
514
|
newVersionEntry,
|
|
515
|
+
buildRangeEnd: this.preAggregation.buildRangeEnd,
|
|
505
516
|
};
|
|
506
517
|
}
|
|
507
|
-
async refreshImplStoreInSourceStrategy(client, newVersionEntry, saveCancelFn,
|
|
518
|
+
async refreshImplStoreInSourceStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
508
519
|
const [loadSql, params] = Array.isArray(this.preAggregation.loadSql) ? this.preAggregation.loadSql : [this.preAggregation.loadSql, []];
|
|
509
520
|
const targetTableName = this.targetTableName(newVersionEntry);
|
|
510
521
|
const query = QueryCache_1.QueryCache.replacePreAggregationTableNames(loadSql, this.preAggregationsTablesToTempTables)
|
|
@@ -526,7 +537,7 @@ class PreAggregationLoader {
|
|
|
526
537
|
/**
|
|
527
538
|
* Strategy to copy pre-aggregation from source db (with write permissions) to external data
|
|
528
539
|
*/
|
|
529
|
-
async refreshImplTempTableExternalStrategy(client, newVersionEntry, saveCancelFn,
|
|
540
|
+
async refreshImplTempTableExternalStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
530
541
|
const [loadSql, params] = Array.isArray(this.preAggregation.loadSql) ? this.preAggregation.loadSql : [this.preAggregation.loadSql, []];
|
|
531
542
|
await client.createSchemaIfNotExists(this.preAggregation.preAggregationsSchema);
|
|
532
543
|
const targetTableName = this.targetTableName(newVersionEntry);
|
|
@@ -536,7 +547,7 @@ class PreAggregationLoader {
|
|
|
536
547
|
this.logExecutingSql(queryOptions);
|
|
537
548
|
await saveCancelFn(client.loadPreAggregationIntoTable(targetTableName, query, params, queryOptions));
|
|
538
549
|
try {
|
|
539
|
-
const tableData = await this.downloadTempExternalPreAggregation(client, newVersionEntry,
|
|
550
|
+
const tableData = await this.downloadTempExternalPreAggregation(client, newVersionEntry, saveCancelFn, queryOptions);
|
|
540
551
|
try {
|
|
541
552
|
await this.uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn, queryOptions);
|
|
542
553
|
}
|
|
@@ -555,7 +566,7 @@ class PreAggregationLoader {
|
|
|
555
566
|
/**
|
|
556
567
|
* Strategy to copy pre-aggregation from source db (for read-only permissions) to external data
|
|
557
568
|
*/
|
|
558
|
-
async refreshImplStreamExternalStrategy(client, newVersionEntry, saveCancelFn,
|
|
569
|
+
async refreshImplStreamExternalStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
559
570
|
const [sql, params] = Array.isArray(this.preAggregation.sql) ? this.preAggregation.sql : [this.preAggregation.sql, []];
|
|
560
571
|
// @todo Deprecated, BaseDriver already implements it, before remove we need to add check for factoryDriver
|
|
561
572
|
if (!client.downloadQueryResults) {
|
|
@@ -600,7 +611,7 @@ class PreAggregationLoader {
|
|
|
600
611
|
/**
|
|
601
612
|
* Create table (for db with write permissions) and extract data via memory/stream/unload
|
|
602
613
|
*/
|
|
603
|
-
async downloadTempExternalPreAggregation(client, newVersionEntry,
|
|
614
|
+
async downloadTempExternalPreAggregation(client, newVersionEntry, saveCancelFn, queryOptions) {
|
|
604
615
|
// @todo Deprecated, BaseDriver already implements it, before remove we need to add check for factoryDriver
|
|
605
616
|
if (!client.downloadTable) {
|
|
606
617
|
throw new Error('Can\'t load external pre-aggregation: source driver doesn\'t support downloadTable()');
|
|
@@ -617,7 +628,7 @@ class PreAggregationLoader {
|
|
|
617
628
|
else if (capabilities.streamImport && client.stream) {
|
|
618
629
|
tableData = await saveCancelFn(client.stream(`SELECT * FROM ${table}`, [], this.getStreamingOptions()));
|
|
619
630
|
if (client.unload) {
|
|
620
|
-
const stream = new StreamObjectsCounter_1.LargeStreamWarning(preAggregation.preAggregationId, (msg) => {
|
|
631
|
+
const stream = new StreamObjectsCounter_1.LargeStreamWarning(this.preAggregation.preAggregationId, (msg) => {
|
|
621
632
|
this.logger('Downloading external pre-aggregation warning', {
|
|
622
633
|
...queryOptions,
|
|
623
634
|
error: msg
|
|
@@ -711,7 +722,10 @@ exports.PreAggregationLoader = PreAggregationLoader;
|
|
|
711
722
|
class PreAggregationPartitionRangeLoader {
|
|
712
723
|
constructor(redisPrefix, driverFactory, logger, queryCache,
|
|
713
724
|
// eslint-disable-next-line no-use-before-define
|
|
714
|
-
preAggregations, preAggregation, preAggregationsTablesToTempTables, loadCache, options = {
|
|
725
|
+
preAggregations, preAggregation, preAggregationsTablesToTempTables, loadCache, options = {
|
|
726
|
+
maxPartitions: 10000,
|
|
727
|
+
maxSourceRowLimit: 10000,
|
|
728
|
+
}) {
|
|
715
729
|
this.redisPrefix = redisPrefix;
|
|
716
730
|
this.driverFactory = driverFactory;
|
|
717
731
|
this.logger = logger;
|
|
@@ -723,11 +737,16 @@ class PreAggregationPartitionRangeLoader {
|
|
|
723
737
|
this.options = options;
|
|
724
738
|
this.waitForRenew = options.waitForRenew;
|
|
725
739
|
this.requestId = options.requestId;
|
|
740
|
+
this.lambdaQuery = options.lambdaQuery;
|
|
726
741
|
this.dataSource = preAggregation.dataSource;
|
|
727
742
|
}
|
|
728
743
|
async loadRangeQuery(rangeQuery, partitionRange) {
|
|
729
744
|
const [query, values, queryOptions] = rangeQuery;
|
|
730
|
-
|
|
745
|
+
const invalidate = this.preAggregation.invalidateKeyQueries &&
|
|
746
|
+
this.preAggregation.invalidateKeyQueries[0]
|
|
747
|
+
? this.preAggregation.invalidateKeyQueries[0].slice(0, 2)
|
|
748
|
+
: false;
|
|
749
|
+
return this.queryCache.cacheQueryResult(query, values, QueryCache_1.QueryCache.queryCacheKey({ query, values, invalidate }), 24 * 60 * 60, {
|
|
731
750
|
renewalThreshold: this.queryCache.options.refreshKeyRenewalThreshold
|
|
732
751
|
|| (queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.renewalThreshold) || 24 * 60 * 60,
|
|
733
752
|
waitForRenew: this.waitForRenew,
|
|
@@ -736,7 +755,7 @@ class PreAggregationPartitionRangeLoader {
|
|
|
736
755
|
dataSource: this.dataSource,
|
|
737
756
|
useInMemory: true,
|
|
738
757
|
external: queryOptions === null || queryOptions === void 0 ? void 0 : queryOptions.external,
|
|
739
|
-
renewalKey: partitionRange ? await this.getInvalidationKeyValues(partitionRange) : null
|
|
758
|
+
renewalKey: partitionRange ? await this.getInvalidationKeyValues(partitionRange) : null,
|
|
740
759
|
});
|
|
741
760
|
}
|
|
742
761
|
getInvalidationKeyValues(range) {
|
|
@@ -779,32 +798,38 @@ class PreAggregationPartitionRangeLoader {
|
|
|
779
798
|
}), {
|
|
780
799
|
...options,
|
|
781
800
|
renewalThreshold: (options === null || options === void 0 ? void 0 : options.incremental) && updateWindowToBoundary < new Date() ?
|
|
782
|
-
// if updateWindowToBoundary passed just moments ago we want to renew it earlier in case
|
|
783
|
-
// and db clock don't match
|
|
801
|
+
// if updateWindowToBoundary passed just moments ago we want to renew it earlier in case
|
|
802
|
+
// of server and db clock don't match
|
|
784
803
|
Math.min(Math.round((new Date().getTime() - updateWindowToBoundary.getTime()) / 1000), options === null || options === void 0 ? void 0 : options.renewalThresholdOutsideUpdateWindow) : options === null || options === void 0 ? void 0 : options.renewalThreshold
|
|
785
804
|
}];
|
|
786
805
|
}
|
|
787
|
-
partitionPreAggregationDescription(range) {
|
|
806
|
+
partitionPreAggregationDescription(range, buildRange) {
|
|
788
807
|
const partitionTableName = PreAggregationPartitionRangeLoader.partitionTableName(this.preAggregation.tableName, this.preAggregation.partitionGranularity, range);
|
|
808
|
+
const [_, buildRangeEnd] = buildRange;
|
|
809
|
+
const loadRange = [...range];
|
|
810
|
+
if (this.preAggregation.unionWithSourceData && buildRangeEnd < range[1]) {
|
|
811
|
+
loadRange[1] = buildRangeEnd;
|
|
812
|
+
}
|
|
789
813
|
return {
|
|
790
814
|
...this.preAggregation,
|
|
791
815
|
tableName: partitionTableName,
|
|
792
816
|
loadSql: this.preAggregation.loadSql &&
|
|
793
|
-
this.replacePartitionSqlAndParams(this.preAggregation.loadSql,
|
|
817
|
+
this.replacePartitionSqlAndParams(this.preAggregation.loadSql, loadRange, partitionTableName),
|
|
794
818
|
sql: this.preAggregation.sql &&
|
|
795
|
-
this.replacePartitionSqlAndParams(this.preAggregation.sql,
|
|
819
|
+
this.replacePartitionSqlAndParams(this.preAggregation.sql, loadRange, partitionTableName),
|
|
796
820
|
invalidateKeyQueries: (this.preAggregation.invalidateKeyQueries || [])
|
|
797
821
|
.map(q => this.replacePartitionSqlAndParams(q, range, partitionTableName)),
|
|
798
822
|
indexesSql: (this.preAggregation.indexesSql || [])
|
|
799
823
|
.map(q => ({ ...q, sql: this.replacePartitionSqlAndParams(q.sql, range, partitionTableName) })),
|
|
800
824
|
previewSql: this.preAggregation.previewSql &&
|
|
801
|
-
this.replacePartitionSqlAndParams(this.preAggregation.previewSql, range, partitionTableName)
|
|
825
|
+
this.replacePartitionSqlAndParams(this.preAggregation.previewSql, range, partitionTableName),
|
|
826
|
+
buildRangeEnd,
|
|
802
827
|
};
|
|
803
828
|
}
|
|
804
829
|
async loadPreAggregations() {
|
|
805
830
|
if (this.preAggregation.partitionGranularity && !this.preAggregation.expandedPartition) {
|
|
806
|
-
const partitionRanges = await this.partitionRanges();
|
|
807
|
-
const partitionLoaders = partitionRanges.map(range => new PreAggregationLoader(this.redisPrefix, this.driverFactory, this.logger, this.queryCache, this.preAggregations, this.partitionPreAggregationDescription(range), this.preAggregationsTablesToTempTables, this.loadCache, this.options));
|
|
831
|
+
const { buildRange, partitionRanges } = await this.partitionRanges();
|
|
832
|
+
const partitionLoaders = partitionRanges.map(range => new PreAggregationLoader(this.redisPrefix, this.driverFactory, this.logger, this.queryCache, this.preAggregations, this.partitionPreAggregationDescription(range, buildRange), this.preAggregationsTablesToTempTables, this.loadCache, this.options));
|
|
808
833
|
const resolveResults = await Promise.all(partitionLoaders.map(l => l.loadPreAggregation(false)));
|
|
809
834
|
const loadResults = resolveResults.filter(res => res !== null);
|
|
810
835
|
if (this.options.externalRefresh && loadResults.length === 0) {
|
|
@@ -813,25 +838,65 @@ class PreAggregationPartitionRangeLoader {
|
|
|
813
838
|
'built yet. Please make sure your refresh worker is configured ' +
|
|
814
839
|
'correctly and running.');
|
|
815
840
|
}
|
|
816
|
-
const allTableTargetNames = loadResults
|
|
817
|
-
|
|
841
|
+
const allTableTargetNames = loadResults.map(targetTableName => targetTableName.targetTableName);
|
|
842
|
+
let lastUpdatedAt = getLastUpdatedAtTimestamp(loadResults.map(r => r.lastUpdatedAt));
|
|
843
|
+
let lambdaTable;
|
|
844
|
+
if (this.lambdaQuery && loadResults.length > 0) {
|
|
845
|
+
const { buildRangeEnd } = loadResults[loadResults.length - 1];
|
|
846
|
+
lambdaTable = await this.downloadLambdaTable(buildRangeEnd);
|
|
847
|
+
allTableTargetNames.push(lambdaTable.name);
|
|
848
|
+
lastUpdatedAt = Date.now();
|
|
849
|
+
}
|
|
818
850
|
const unionTargetTableName = allTableTargetNames
|
|
819
851
|
.map(targetTableName => `SELECT * FROM ${targetTableName}`)
|
|
820
852
|
.join(' UNION ALL ');
|
|
821
853
|
return {
|
|
822
854
|
targetTableName: allTableTargetNames.length === 1 ? allTableTargetNames[0] : `(${unionTargetTableName})`,
|
|
823
855
|
refreshKeyValues: loadResults.map(t => t.refreshKeyValues),
|
|
824
|
-
lastUpdatedAt
|
|
856
|
+
lastUpdatedAt,
|
|
857
|
+
buildRangeEnd: undefined,
|
|
858
|
+
lambdaTable,
|
|
825
859
|
};
|
|
826
860
|
}
|
|
827
861
|
else {
|
|
828
862
|
return new PreAggregationLoader(this.redisPrefix, this.driverFactory, this.logger, this.queryCache, this.preAggregations, this.preAggregation, this.preAggregationsTablesToTempTables, this.loadCache, this.options).loadPreAggregation(true);
|
|
829
863
|
}
|
|
830
864
|
}
|
|
865
|
+
/**
|
|
866
|
+
* Downloads the lambda table from the source DB.
|
|
867
|
+
*/
|
|
868
|
+
async downloadLambdaTable(fromDate) {
|
|
869
|
+
const { sqlAndParams, cacheKeyQueries } = this.lambdaQuery;
|
|
870
|
+
const [query, params] = sqlAndParams;
|
|
871
|
+
const values = params.map((p) => {
|
|
872
|
+
if (p === shared_1.FROM_PARTITION_RANGE) {
|
|
873
|
+
return fromDate;
|
|
874
|
+
}
|
|
875
|
+
if (p === shared_1.MAX_SOURCE_ROW_LIMIT) {
|
|
876
|
+
return this.options.maxSourceRowLimit;
|
|
877
|
+
}
|
|
878
|
+
return p;
|
|
879
|
+
});
|
|
880
|
+
const { data } = await this.queryCache.renewQuery(query, values, cacheKeyQueries, 60 * 60, [query, values], undefined, {
|
|
881
|
+
requestId: this.requestId,
|
|
882
|
+
skipRefreshKeyWaitForRenew: false,
|
|
883
|
+
dataSource: this.dataSource,
|
|
884
|
+
external: false,
|
|
885
|
+
useCsvQuery: true,
|
|
886
|
+
});
|
|
887
|
+
if (data.rowCount === this.options.maxSourceRowLimit) {
|
|
888
|
+
throw new Error(`The maximum number of source rows ${this.options.maxSourceRowLimit} was reached for ${this.preAggregation.preAggregationId}`);
|
|
889
|
+
}
|
|
890
|
+
return {
|
|
891
|
+
name: `${exports.LAMBDA_TABLE_PREFIX}_${this.preAggregation.tableName.replace('.', '_')}`,
|
|
892
|
+
columns: data.types,
|
|
893
|
+
csvRows: data.csvRows,
|
|
894
|
+
};
|
|
895
|
+
}
|
|
831
896
|
async partitionPreAggregations() {
|
|
832
897
|
if (this.preAggregation.partitionGranularity && !this.preAggregation.expandedPartition) {
|
|
833
|
-
const partitionRanges = await this.partitionRanges();
|
|
834
|
-
return partitionRanges.map(range => this.partitionPreAggregationDescription(range));
|
|
898
|
+
const { buildRange, partitionRanges } = await this.partitionRanges();
|
|
899
|
+
return partitionRanges.map(range => this.partitionPreAggregationDescription(range, buildRange));
|
|
835
900
|
}
|
|
836
901
|
else {
|
|
837
902
|
return [this.preAggregation];
|
|
@@ -840,7 +905,7 @@ class PreAggregationPartitionRangeLoader {
|
|
|
840
905
|
async partitionRanges() {
|
|
841
906
|
const buildRange = await this.loadBuildRange();
|
|
842
907
|
if (!buildRange[0] || !buildRange[1]) {
|
|
843
|
-
return [];
|
|
908
|
+
return { buildRange, partitionRanges: [] };
|
|
844
909
|
}
|
|
845
910
|
let dateRange = PreAggregationPartitionRangeLoader.intersectDateRanges(buildRange, this.preAggregation.matchedTimeDimensionDateRange);
|
|
846
911
|
if (!dateRange) {
|
|
@@ -848,7 +913,11 @@ class PreAggregationPartitionRangeLoader {
|
|
|
848
913
|
// use last partition so outer query can receive expected table structure.
|
|
849
914
|
dateRange = [buildRange[1], buildRange[1]];
|
|
850
915
|
}
|
|
851
|
-
|
|
916
|
+
const partitionRanges = PreAggregationPartitionRangeLoader.timeSeries(this.preAggregation.partitionGranularity, dateRange);
|
|
917
|
+
if (partitionRanges.length > this.options.maxPartitions) {
|
|
918
|
+
throw new Error(`The maximum number of partitions (${this.options.maxPartitions}) was reached for the pre-aggregation`);
|
|
919
|
+
}
|
|
920
|
+
return { buildRange: dateRange, partitionRanges };
|
|
852
921
|
}
|
|
853
922
|
async loadBuildRange() {
|
|
854
923
|
const { preAggregationStartEndQueries } = this.preAggregation;
|
|
@@ -860,9 +929,12 @@ class PreAggregationPartitionRangeLoader {
|
|
|
860
929
|
const [rangeStart, rangeEnd] = await Promise.all(preAggregationStartEndQueries.map(async (rangeQuery, i) => PreAggregationPartitionRangeLoader.extractDate(await this.loadRangeQuery(rangeQuery, i === 0 ? wholeSeriesRanges[0] : wholeSeriesRanges[wholeSeriesRanges.length - 1]))));
|
|
861
930
|
return this.orNowIfEmpty([rangeStart, rangeEnd]);
|
|
862
931
|
}
|
|
932
|
+
now() {
|
|
933
|
+
return shared_1.utcToLocalTimeZone(this.preAggregation.timezone, 'YYYY-MM-DDTHH:mm:ss.SSS', new Date().toJSON().substring(0, 23));
|
|
934
|
+
}
|
|
863
935
|
orNowIfEmpty(dateRange) {
|
|
864
936
|
if (!dateRange[0] && !dateRange[1]) {
|
|
865
|
-
const now =
|
|
937
|
+
const now = this.now();
|
|
866
938
|
return [now, now];
|
|
867
939
|
}
|
|
868
940
|
if (!dateRange[0]) {
|
|
@@ -973,16 +1045,21 @@ class PreAggregations {
|
|
|
973
1045
|
};
|
|
974
1046
|
let queryParamsReplacement = null;
|
|
975
1047
|
const preAggregationsTablesToTempTablesPromise = preAggregations.map((p, i) => (preAggregationsTablesToTempTables) => {
|
|
1048
|
+
var _a;
|
|
976
1049
|
const loader = new PreAggregationPartitionRangeLoader(this.redisPrefix, () => this.driverFactory(p.dataSource || 'default'), this.logger, this.queryCache, this, p, preAggregationsTablesToTempTables, getLoadCacheByDataSource(p.dataSource, p.preAggregationsSchema), {
|
|
1050
|
+
maxPartitions: this.options.maxPartitions,
|
|
1051
|
+
maxSourceRowLimit: this.options.maxSourceRowLimit,
|
|
977
1052
|
waitForRenew: queryBody.renewQuery,
|
|
978
1053
|
// TODO workaround to avoid continuous waiting on building pre-aggregation dependencies
|
|
979
1054
|
forceBuild: i === preAggregations.length - 1 ? queryBody.forceBuildPreAggregations : false,
|
|
980
1055
|
requestId: queryBody.requestId,
|
|
981
1056
|
metadata: queryBody.metadata,
|
|
982
1057
|
orphanedTimeout: queryBody.orphanedTimeout,
|
|
1058
|
+
lambdaQuery: ((_a = queryBody.lambdaQueries) !== null && _a !== void 0 ? _a : {})[p.preAggregationId],
|
|
983
1059
|
externalRefresh: this.externalRefresh
|
|
984
1060
|
});
|
|
985
|
-
const preAggregationPromise =
|
|
1061
|
+
const preAggregationPromise = async () => {
|
|
1062
|
+
const loadResult = await loader.loadPreAggregations();
|
|
986
1063
|
const usedPreAggregation = {
|
|
987
1064
|
...loadResult,
|
|
988
1065
|
type: p.type,
|
|
@@ -992,7 +1069,7 @@ class PreAggregations {
|
|
|
992
1069
|
queryParamsReplacement = await loader.replaceQueryBuildRangeParams(queryBody.values);
|
|
993
1070
|
}
|
|
994
1071
|
return [p.tableName, usedPreAggregation];
|
|
995
|
-
}
|
|
1072
|
+
};
|
|
996
1073
|
return preAggregationPromise().then(res => preAggregationsTablesToTempTables.concat([res]));
|
|
997
1074
|
}).reduce((promise, fn) => promise.then(fn), Promise.resolve([]));
|
|
998
1075
|
return preAggregationsTablesToTempTablesPromise.then(preAggregationsTablesToTempTables => ({
|
|
@@ -1027,9 +1104,11 @@ class PreAggregations {
|
|
|
1027
1104
|
};
|
|
1028
1105
|
const expandedPreAggregations = await Promise.all(preAggregations.map(p => {
|
|
1029
1106
|
const loader = new PreAggregationPartitionRangeLoader(this.redisPrefix, () => this.driverFactory(p.dataSource || 'default'), this.logger, this.queryCache, this, p, [], getLoadCacheByDataSource(p.dataSource, p.preAggregationsSchema), {
|
|
1107
|
+
maxPartitions: this.options.maxPartitions,
|
|
1108
|
+
maxSourceRowLimit: this.options.maxSourceRowLimit,
|
|
1030
1109
|
waitForRenew: queryBody.renewQuery,
|
|
1031
1110
|
requestId: queryBody.requestId,
|
|
1032
|
-
externalRefresh: this.externalRefresh
|
|
1111
|
+
externalRefresh: this.externalRefresh,
|
|
1033
1112
|
});
|
|
1034
1113
|
return loader.partitionPreAggregations();
|
|
1035
1114
|
}));
|
|
@@ -1045,9 +1124,9 @@ class PreAggregations {
|
|
|
1045
1124
|
async getQueue(dataSource = 'default') {
|
|
1046
1125
|
if (!this.queue[dataSource]) {
|
|
1047
1126
|
this.queue[dataSource] = QueryCache_1.QueryCache.createQueue(`SQL_PRE_AGGREGATIONS_${this.redisPrefix}_${dataSource}`, () => this.driverFactory(dataSource), (client, q) => {
|
|
1048
|
-
const { preAggregation, preAggregationsTablesToTempTables, newVersionEntry, requestId, invalidationKeys } = q;
|
|
1049
|
-
const loader = new PreAggregationLoader(this.redisPrefix, () => this.driverFactory(dataSource), this.logger, this.queryCache, this, preAggregation, preAggregationsTablesToTempTables, new PreAggregationLoadCache(this.redisPrefix, () => this.driverFactory(dataSource), this.queryCache, this, { requestId, dataSource }), { requestId, externalRefresh: this.externalRefresh });
|
|
1050
|
-
return loader.refresh(
|
|
1127
|
+
const { preAggregation, preAggregationsTablesToTempTables, newVersionEntry, requestId, invalidationKeys, buildRangeEnd } = q;
|
|
1128
|
+
const loader = new PreAggregationLoader(this.redisPrefix, () => this.driverFactory(dataSource), this.logger, this.queryCache, this, preAggregation, preAggregationsTablesToTempTables, new PreAggregationLoadCache(this.redisPrefix, () => this.driverFactory(dataSource), this.queryCache, this, { requestId, dataSource }), { requestId, externalRefresh: this.externalRefresh, buildRangeEnd });
|
|
1129
|
+
return loader.refresh(newVersionEntry, invalidationKeys, client);
|
|
1051
1130
|
}, {
|
|
1052
1131
|
concurrency: 1,
|
|
1053
1132
|
logger: this.logger,
|