@cubejs-backend/query-orchestrator 1.2.12 → 1.2.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/dist/src/orchestrator/PreAggregationLoadCache.d.ts +42 -0
  2. package/dist/src/orchestrator/PreAggregationLoadCache.d.ts.map +1 -0
  3. package/dist/src/orchestrator/PreAggregationLoadCache.js +172 -0
  4. package/dist/src/orchestrator/PreAggregationLoadCache.js.map +1 -0
  5. package/dist/src/orchestrator/PreAggregationLoader.d.ts +105 -0
  6. package/dist/src/orchestrator/PreAggregationLoader.d.ts.map +1 -0
  7. package/dist/src/orchestrator/PreAggregationLoader.js +742 -0
  8. package/dist/src/orchestrator/PreAggregationLoader.js.map +1 -0
  9. package/dist/src/orchestrator/PreAggregationPartitionRangeLoader.d.ts +65 -0
  10. package/dist/src/orchestrator/PreAggregationPartitionRangeLoader.d.ts.map +1 -0
  11. package/dist/src/orchestrator/PreAggregationPartitionRangeLoader.js +355 -0
  12. package/dist/src/orchestrator/PreAggregationPartitionRangeLoader.js.map +1 -0
  13. package/dist/src/orchestrator/PreAggregations.d.ts +35 -223
  14. package/dist/src/orchestrator/PreAggregations.d.ts.map +1 -1
  15. package/dist/src/orchestrator/PreAggregations.js +17 -1261
  16. package/dist/src/orchestrator/PreAggregations.js.map +1 -1
  17. package/dist/src/orchestrator/QueryCache.d.ts +14 -4
  18. package/dist/src/orchestrator/QueryCache.d.ts.map +1 -1
  19. package/dist/src/orchestrator/QueryCache.js +1 -1
  20. package/dist/src/orchestrator/QueryCache.js.map +1 -1
  21. package/dist/src/orchestrator/QueryQueue.js +1 -1
  22. package/dist/src/orchestrator/QueryQueue.js.map +1 -1
  23. package/dist/src/orchestrator/index.d.ts +3 -0
  24. package/dist/src/orchestrator/index.d.ts.map +1 -1
  25. package/dist/src/orchestrator/index.js +3 -0
  26. package/dist/src/orchestrator/index.js.map +1 -1
  27. package/package.json +6 -6
@@ -3,15 +3,15 @@ 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 = exports.LAMBDA_TABLE_PREFIX = void 0;
7
- const crypto_1 = __importDefault(require("crypto"));
6
+ exports.PreAggregations = exports.tablesToVersionEntries = exports.getStructureVersion = exports.getLastUpdatedAtTimestamp = exports.version = exports.LAMBDA_TABLE_PREFIX = void 0;
8
7
  const ramda_1 = __importDefault(require("ramda"));
8
+ const crypto_1 = __importDefault(require("crypto"));
9
9
  const shared_1 = require("@cubejs-backend/shared");
10
- const base_driver_1 = require("@cubejs-backend/base-driver");
11
10
  const lru_cache_1 = __importDefault(require("lru-cache"));
12
11
  const QueryCache_1 = require("./QueryCache");
13
- const ContinueWaitError_1 = require("./ContinueWaitError");
14
- const StreamObjectsCounter_1 = require("./StreamObjectsCounter");
12
+ const PreAggregationPartitionRangeLoader_1 = require("./PreAggregationPartitionRangeLoader");
13
+ const PreAggregationLoader_1 = require("./PreAggregationLoader");
14
+ const PreAggregationLoadCache_1 = require("./PreAggregationLoadCache");
15
15
  /// Name of the inline table containing the lambda rows.
16
16
  exports.LAMBDA_TABLE_PREFIX = 'lambda';
17
17
  function encodeTimeStamp(time) {
@@ -42,11 +42,7 @@ function version(cacheKey) {
42
42
  result += hashCharset.charAt(residue % 32);
43
43
  return result;
44
44
  }
45
- // There’re community developed and custom drivers which not always up-to-date with latest BaseDriver.
46
- // Extra defence for drivers that don't expose now() yet.
47
- function nowTimestamp(client) {
48
- return client.nowTimestamp?.() ?? new Date().getTime();
49
- }
45
+ exports.version = version;
50
46
  // Returns the oldest timestamp, if any.
51
47
  function getLastUpdatedAtTimestamp(timestamps) {
52
48
  timestamps = timestamps.filter(t => t !== undefined);
@@ -71,6 +67,7 @@ function getStructureVersion(preAggregation) {
71
67
  }
72
68
  return version(versionArray.length === 1 ? versionArray[0] : versionArray);
73
69
  }
70
+ exports.getStructureVersion = getStructureVersion;
74
71
  const tablesToVersionEntries = (schema, tables) => ramda_1.default.sortBy(table => -table.last_updated_at, tables.map(table => {
75
72
  const match = (table.table_name || table.TABLE_NAME).match(/(.+)_(.+)_(.+)_(.+)/);
76
73
  if (!match) {
@@ -93,1247 +90,7 @@ const tablesToVersionEntries = (schema, tables) => ramda_1.default.sortBy(table
93
90
  }
94
91
  return entity;
95
92
  }).filter(ramda_1.default.identity));
96
- class PreAggregationLoadCache {
97
- redisPrefix;
98
- driverFactory;
99
- queryCache;
100
- // eslint-disable-next-line no-use-before-define
101
- preAggregations;
102
- queryResults;
103
- externalDriverFactory;
104
- requestId;
105
- versionEntries;
106
- tables;
107
- tableColumnTypes;
108
- // TODO this is in memory cache structure as well however it depends on
109
- // data source only and load cache is per data source for now.
110
- // Make it per data source key in case load cache scope is broaden.
111
- queryStageState;
112
- dataSource;
113
- tablePrefixes;
114
- constructor(redisPrefix, clientFactory, queryCache, preAggregations, options = { dataSource: 'default' }) {
115
- this.redisPrefix = `${redisPrefix}_${options.dataSource}`;
116
- this.dataSource = options.dataSource;
117
- this.driverFactory = clientFactory;
118
- this.queryCache = queryCache;
119
- this.preAggregations = preAggregations;
120
- this.queryResults = {};
121
- this.externalDriverFactory = preAggregations.externalDriverFactory;
122
- this.requestId = options.requestId;
123
- this.tablePrefixes = options.tablePrefixes;
124
- this.versionEntries = {};
125
- this.tables = {};
126
- this.tableColumnTypes = {};
127
- }
128
- async tablesFromCache(preAggregation, forceRenew) {
129
- let tables = forceRenew ? null : await this.queryCache.getCacheDriver().get(this.tablesCachePrefixKey(preAggregation));
130
- if (!tables) {
131
- tables = await this.preAggregations.getLoadCacheQueue(this.dataSource).executeInQueue('query', `Fetch tables for ${preAggregation.preAggregationsSchema}`, {
132
- preAggregation, requestId: this.requestId
133
- }, 0, { requestId: this.requestId });
134
- }
135
- return tables;
136
- }
137
- async fetchTables(preAggregation) {
138
- if (preAggregation.external && !this.externalDriverFactory) {
139
- throw new Error('externalDriverFactory is not provided. Please use CUBEJS_DEV_MODE=true or provide Cube Store connection env variables for production usage.');
140
- }
141
- const newTables = await this.fetchTablesNoCache(preAggregation);
142
- await this.queryCache.getCacheDriver().set(this.tablesCachePrefixKey(preAggregation), newTables, this.preAggregations.options.preAggregationsSchemaCacheExpire || 60 * 60);
143
- return newTables;
144
- }
145
- async fetchTablesNoCache(preAggregation) {
146
- const client = preAggregation.external ?
147
- await this.externalDriverFactory() :
148
- await this.driverFactory();
149
- if (this.tablePrefixes && client.getPrefixTablesQuery && this.preAggregations.options.skipExternalCacheAndQueue) {
150
- return client.getPrefixTablesQuery(preAggregation.preAggregationsSchema, this.tablePrefixes);
151
- }
152
- return client.getTablesQuery(preAggregation.preAggregationsSchema);
153
- }
154
- tablesCachePrefixKey(preAggregation) {
155
- return this.queryCache.getKey('SQL_PRE_AGGREGATIONS_TABLES', `${preAggregation.dataSource}${preAggregation.preAggregationsSchema}${preAggregation.external ? '_EXT' : ''}`);
156
- }
157
- async getTablesQuery(preAggregation) {
158
- const redisKey = this.tablesCachePrefixKey(preAggregation);
159
- if (!this.tables[redisKey]) {
160
- const tables = this.preAggregations.options.skipExternalCacheAndQueue && preAggregation.external ?
161
- await this.fetchTablesNoCache(preAggregation) :
162
- await this.tablesFromCache(preAggregation);
163
- if (tables === undefined) {
164
- throw new Error('Pre-aggregation tables are undefined.');
165
- }
166
- this.tables[redisKey] = tables;
167
- }
168
- return this.tables[redisKey];
169
- }
170
- async getTableColumnTypes(preAggregation, tableName) {
171
- const prefixKey = this.tablesCachePrefixKey(preAggregation);
172
- if (!this.tableColumnTypes[prefixKey]?.[tableName]) {
173
- if (!this.preAggregations.options.skipExternalCacheAndQueue && preAggregation.external) {
174
- throw new Error(`Lambda union with source data feature is supported only by external rollups stored in Cube Store but was invoked for '${preAggregation.preAggregationId}'`);
175
- }
176
- const client = await this.externalDriverFactory();
177
- const columnTypes = await client.tableColumnTypes(tableName);
178
- if (!this.tableColumnTypes[prefixKey]) {
179
- this.tableColumnTypes[prefixKey] = {};
180
- }
181
- this.tableColumnTypes[prefixKey][tableName] = columnTypes;
182
- }
183
- return this.tableColumnTypes[prefixKey][tableName];
184
- }
185
- async calculateVersionEntries(preAggregation) {
186
- let versionEntries = tablesToVersionEntries(preAggregation.preAggregationsSchema, await this.getTablesQuery(preAggregation));
187
- // It presumes strong consistency guarantees for external pre-aggregation tables ingestion
188
- if (!preAggregation.external) {
189
- // eslint-disable-next-line
190
- const [active, toProcess, queries] = await this.fetchQueryStageState();
191
- const targetTableNamesInQueue = (Object.keys(queries))
192
- // eslint-disable-next-line no-use-before-define
193
- .map(q => PreAggregations.targetTableName(queries[q].query.newVersionEntry));
194
- versionEntries = versionEntries.filter(
195
- // eslint-disable-next-line no-use-before-define
196
- e => targetTableNamesInQueue.indexOf(PreAggregations.targetTableName(e)) === -1);
197
- }
198
- const byContent = {};
199
- const byStructure = {};
200
- const byTableName = {};
201
- versionEntries.forEach(e => {
202
- const contentKey = `${e.table_name}_${e.content_version}`;
203
- if (!byContent[contentKey]) {
204
- byContent[contentKey] = e;
205
- }
206
- const structureKey = `${e.table_name}_${e.structure_version}`;
207
- if (!byStructure[structureKey]) {
208
- byStructure[structureKey] = e;
209
- }
210
- if (!byTableName[e.table_name]) {
211
- byTableName[e.table_name] = e;
212
- }
213
- });
214
- return { versionEntries, byContent, byStructure, byTableName };
215
- }
216
- async getVersionEntries(preAggregation) {
217
- if (this.tablePrefixes && !this.tablePrefixes.find(p => preAggregation.tableName.split('.')[1].startsWith(p))) {
218
- throw new Error(`Load cache tries to load table ${preAggregation.tableName} outside of tablePrefixes filter: ${this.tablePrefixes.join(', ')}`);
219
- }
220
- const redisKey = this.tablesCachePrefixKey(preAggregation);
221
- if (!this.versionEntries[redisKey]) {
222
- this.versionEntries[redisKey] = this.calculateVersionEntries(preAggregation).catch(e => {
223
- delete this.versionEntries[redisKey];
224
- throw e;
225
- });
226
- }
227
- return this.versionEntries[redisKey];
228
- }
229
- async keyQueryResult(sqlQuery, waitForRenew, priority) {
230
- const [query, values, queryOptions] = Array.isArray(sqlQuery) ? sqlQuery : [sqlQuery, [], {}];
231
- if (!this.queryResults[this.queryCache.queryRedisKey([query, values])]) {
232
- this.queryResults[this.queryCache.queryRedisKey([query, values])] = await this.queryCache.cacheQueryResult(query, values, [query, values], 60 * 60, {
233
- renewalThreshold: this.queryCache.options.refreshKeyRenewalThreshold
234
- || queryOptions?.renewalThreshold || 2 * 60,
235
- renewalKey: [query, values],
236
- waitForRenew,
237
- priority,
238
- requestId: this.requestId,
239
- dataSource: this.dataSource,
240
- useInMemory: true,
241
- external: queryOptions?.external
242
- });
243
- }
244
- return this.queryResults[this.queryCache.queryRedisKey([query, values])];
245
- }
246
- hasKeyQueryResult(keyQuery) {
247
- return !!this.queryResults[this.queryCache.queryRedisKey(keyQuery)];
248
- }
249
- async getQueryStage(stageQueryKey) {
250
- const queue = await this.preAggregations.getQueue(this.dataSource);
251
- await this.fetchQueryStageState(queue);
252
- return queue.getQueryStage(stageQueryKey, undefined, this.queryStageState);
253
- }
254
- async fetchQueryStageState(queue) {
255
- queue = queue || await this.preAggregations.getQueue(this.dataSource);
256
- if (!this.queryStageState) {
257
- this.queryStageState = await queue.fetchQueryStageState();
258
- }
259
- return this.queryStageState;
260
- }
261
- async reset(preAggregation) {
262
- await this.tablesFromCache(preAggregation, true);
263
- this.tables = {};
264
- this.tableColumnTypes = {};
265
- this.queryStageState = undefined;
266
- this.versionEntries = {};
267
- }
268
- }
269
- class PreAggregationLoader {
270
- redisPrefix;
271
- driverFactory;
272
- logger;
273
- queryCache;
274
- loadCache;
275
- // eslint-disable-next-line no-use-before-define
276
- preAggregations;
277
- preAggregation;
278
- preAggregationsTablesToTempTables;
279
- /**
280
- * Determines whether current instance instantiated for a jobed build query
281
- * (initialized by the /cubejs-system/v1/pre-aggregations/jobs endpoint) or
282
- * not.
283
- */
284
- isJob;
285
- waitForRenew;
286
- forceBuild;
287
- orphanedTimeout;
288
- externalDriverFactory;
289
- requestId;
290
- metadata;
291
- structureVersionPersistTime;
292
- externalRefresh;
293
- constructor(redisPrefix, driverFactory, logger, queryCache,
294
- // eslint-disable-next-line no-use-before-define
295
- preAggregations, preAggregation, preAggregationsTablesToTempTables, loadCache, options = {}) {
296
- this.redisPrefix = redisPrefix;
297
- this.driverFactory = driverFactory;
298
- this.logger = logger;
299
- this.queryCache = queryCache;
300
- this.loadCache = loadCache;
301
- this.preAggregations = preAggregations;
302
- this.preAggregation = preAggregation;
303
- this.preAggregationsTablesToTempTables = preAggregationsTablesToTempTables;
304
- this.isJob = !!options.isJob;
305
- this.waitForRenew = options.waitForRenew;
306
- this.forceBuild = options.forceBuild;
307
- this.orphanedTimeout = options.orphanedTimeout;
308
- this.externalDriverFactory = preAggregations.externalDriverFactory;
309
- this.requestId = options.requestId;
310
- this.metadata = options.metadata;
311
- this.structureVersionPersistTime = preAggregations.structureVersionPersistTime;
312
- this.externalRefresh = options.externalRefresh;
313
- if (this.externalRefresh && this.waitForRenew) {
314
- const message = 'Invalid configuration - when externalRefresh is true, it will not perform a renew, therefore you cannot wait for it using waitForRenew.';
315
- if (['production', 'test'].includes((0, shared_1.getEnv)('nodeEnv'))) {
316
- throw new Error(message);
317
- }
318
- else {
319
- this.logger('Invalid Configuration', {
320
- requestId: this.requestId,
321
- warning: message,
322
- });
323
- this.waitForRenew = false;
324
- }
325
- }
326
- }
327
- async loadPreAggregation(throwOnMissingPartition) {
328
- const notLoadedKey = (this.preAggregation.invalidateKeyQueries || [])
329
- .find(keyQuery => !this.loadCache.hasKeyQueryResult(keyQuery));
330
- if (this.isJob || !(notLoadedKey && !this.waitForRenew)) {
331
- // Case 1: pre-agg build job processing.
332
- // Case 2: either we have no data cached for this rollup or waitForRenew
333
- // is true, either way, synchronously renew what data is needed so that
334
- // the most current data will be returned fo the current request.
335
- const result = await this.loadPreAggregationWithKeys();
336
- const refreshKeyValues = await this.getInvalidationKeyValues();
337
- return {
338
- ...result,
339
- refreshKeyValues,
340
- queryKey: this.isJob
341
- // We need to return a queryKey value for the jobed build query
342
- // (initialized by the /cubejs-system/v1/pre-aggregations/jobs
343
- // endpoint) as a part of the response to make it possible to get a
344
- // query result from the cache by the other API call.
345
- ? this.preAggregationQueryKey(refreshKeyValues)
346
- : undefined,
347
- };
348
- }
349
- else {
350
- // Case 3: pre-agg is exists
351
- const structureVersion = getStructureVersion(this.preAggregation);
352
- const getVersionsStarted = new Date();
353
- const { byStructure } = await this.loadCache.getVersionEntries(this.preAggregation);
354
- this.logger('Load PreAggregations Tables', {
355
- preAggregation: this.preAggregation,
356
- requestId: this.requestId,
357
- duration: (new Date().getTime() - getVersionsStarted.getTime())
358
- });
359
- const versionEntryByStructureVersion = byStructure[`${this.preAggregation.tableName}_${structureVersion}`];
360
- if (this.externalRefresh) {
361
- if (!versionEntryByStructureVersion && throwOnMissingPartition) {
362
- // eslint-disable-next-line no-use-before-define
363
- throw new Error(PreAggregations.noPreAggregationPartitionsBuiltMessage([this.preAggregation]));
364
- }
365
- if (!versionEntryByStructureVersion) {
366
- return null;
367
- }
368
- else {
369
- // the rollups are being maintained independently of this instance of cube.js
370
- // immediately return the latest rollup data that instance already has
371
- return {
372
- targetTableName: this.targetTableName(versionEntryByStructureVersion),
373
- refreshKeyValues: [],
374
- lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
375
- buildRangeEnd: versionEntryByStructureVersion.build_range_end,
376
- };
377
- }
378
- }
379
- if (versionEntryByStructureVersion) {
380
- // this triggers an asyncronous/background load of the pre-aggregation but immediately
381
- // returns the latest data it already has
382
- this.loadPreAggregationWithKeys().catch(e => {
383
- if (!(e instanceof ContinueWaitError_1.ContinueWaitError)) {
384
- this.logger('Error loading pre-aggregation', {
385
- error: (e.stack || e),
386
- preAggregation: this.preAggregation,
387
- requestId: this.requestId
388
- });
389
- }
390
- });
391
- return {
392
- targetTableName: this.targetTableName(versionEntryByStructureVersion),
393
- refreshKeyValues: [],
394
- lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
395
- buildRangeEnd: versionEntryByStructureVersion.build_range_end,
396
- };
397
- }
398
- else {
399
- // no rollup has been built yet - build it synchronously as part of responding to this request
400
- return this.loadPreAggregationWithKeys();
401
- }
402
- }
403
- }
404
- async loadPreAggregationWithKeys() {
405
- const invalidationKeys = await this.getPartitionInvalidationKeyValues();
406
- const contentVersion = this.contentVersion(invalidationKeys);
407
- const structureVersion = getStructureVersion(this.preAggregation);
408
- const versionEntries = await this.loadCache.getVersionEntries(this.preAggregation);
409
- const getVersionEntryByContentVersion = ({ byContent }) => byContent[`${this.preAggregation.tableName}_${contentVersion}`];
410
- const versionEntryByContentVersion = getVersionEntryByContentVersion(versionEntries);
411
- if (versionEntryByContentVersion && !this.forceBuild) {
412
- const targetTableName = this.targetTableName(versionEntryByContentVersion);
413
- // No need to block here
414
- this.updateLastTouch(targetTableName);
415
- return {
416
- targetTableName,
417
- refreshKeyValues: [],
418
- lastUpdatedAt: versionEntryByContentVersion.last_updated_at,
419
- buildRangeEnd: versionEntryByContentVersion.build_range_end,
420
- };
421
- }
422
- if (!this.waitForRenew && !this.forceBuild) {
423
- const versionEntryByStructureVersion = versionEntries.byStructure[`${this.preAggregation.tableName}_${structureVersion}`];
424
- if (versionEntryByStructureVersion) {
425
- const targetTableName = this.targetTableName(versionEntryByStructureVersion);
426
- // No need to block here
427
- this.updateLastTouch(targetTableName);
428
- return {
429
- targetTableName,
430
- refreshKeyValues: [],
431
- lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
432
- buildRangeEnd: versionEntryByStructureVersion.build_range_end,
433
- };
434
- }
435
- }
436
- const client = this.preAggregation.external ?
437
- await this.externalDriverFactory() :
438
- await this.driverFactory();
439
- if (!versionEntries.versionEntries.length) {
440
- await client.createSchemaIfNotExists(this.preAggregation.preAggregationsSchema);
441
- }
442
- // ensure we find appropriate structure version before invalidating anything
443
- const versionEntry = versionEntries.byStructure[`${this.preAggregation.tableName}_${structureVersion}`] ||
444
- versionEntries.byTableName[this.preAggregation.tableName];
445
- const newVersionEntry = {
446
- table_name: this.preAggregation.tableName,
447
- structure_version: structureVersion,
448
- content_version: contentVersion,
449
- last_updated_at: nowTimestamp(client),
450
- naming_version: 2,
451
- };
452
- const mostRecentResult = async () => {
453
- await this.loadCache.reset(this.preAggregation);
454
- const lastVersion = getVersionEntryByContentVersion(await this.loadCache.getVersionEntries(this.preAggregation));
455
- if (!lastVersion) {
456
- throw new Error(`Pre-aggregation table is not found for ${this.preAggregation.tableName} after it was successfully created`);
457
- }
458
- const targetTableName = this.targetTableName(lastVersion);
459
- this.updateLastTouch(targetTableName);
460
- return {
461
- targetTableName,
462
- refreshKeyValues: [],
463
- lastUpdatedAt: lastVersion.last_updated_at,
464
- buildRangeEnd: lastVersion.build_range_end,
465
- };
466
- };
467
- if (this.forceBuild) {
468
- this.logger('Force build pre-aggregation', {
469
- preAggregation: this.preAggregation,
470
- requestId: this.requestId,
471
- metadata: this.metadata,
472
- queryKey: this.preAggregationQueryKey(invalidationKeys),
473
- newVersionEntry
474
- });
475
- if (this.isJob) {
476
- // We don't want to wait for the jobed build query result. So we run the
477
- // executeInQueue method and immediately return the LoadPreAggregationResult object.
478
- this
479
- .executeInQueue(invalidationKeys, this.priority(10), newVersionEntry)
480
- .catch((e) => {
481
- this.logger('Pre-aggregations build job error', {
482
- preAggregation: this.preAggregation,
483
- requestId: this.requestId,
484
- newVersionEntry,
485
- error: (e.stack || e),
486
- });
487
- });
488
- const targetTableName = this.targetTableName(newVersionEntry);
489
- this.updateLastTouch(targetTableName);
490
- return {
491
- targetTableName,
492
- refreshKeyValues: [],
493
- lastUpdatedAt: newVersionEntry.last_updated_at,
494
- buildRangeEnd: this.preAggregation.buildRangeEnd,
495
- };
496
- }
497
- else {
498
- await this.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry);
499
- return mostRecentResult();
500
- }
501
- }
502
- if (versionEntry) {
503
- if (versionEntry.structure_version !== newVersionEntry.structure_version) {
504
- this.logger('Invalidating pre-aggregation structure', {
505
- preAggregation: this.preAggregation,
506
- requestId: this.requestId,
507
- queryKey: this.preAggregationQueryKey(invalidationKeys),
508
- newVersionEntry
509
- });
510
- await this.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry);
511
- return mostRecentResult();
512
- }
513
- else if (versionEntry.content_version !== newVersionEntry.content_version) {
514
- if (this.waitForRenew) {
515
- this.logger('Waiting for pre-aggregation renew', {
516
- preAggregation: this.preAggregation,
517
- requestId: this.requestId,
518
- queryKey: this.preAggregationQueryKey(invalidationKeys),
519
- newVersionEntry
520
- });
521
- await this.executeInQueue(invalidationKeys, this.priority(0), newVersionEntry);
522
- return mostRecentResult();
523
- }
524
- else {
525
- this.scheduleRefresh(invalidationKeys, newVersionEntry);
526
- }
527
- }
528
- }
529
- else {
530
- this.logger('Creating pre-aggregation from scratch', {
531
- preAggregation: this.preAggregation,
532
- requestId: this.requestId,
533
- queryKey: this.preAggregationQueryKey(invalidationKeys),
534
- newVersionEntry
535
- });
536
- await this.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry);
537
- return mostRecentResult();
538
- }
539
- const targetTableName = this.targetTableName(versionEntry);
540
- this.updateLastTouch(targetTableName);
541
- return {
542
- targetTableName,
543
- refreshKeyValues: [],
544
- lastUpdatedAt: versionEntry.last_updated_at,
545
- buildRangeEnd: versionEntry.build_range_end,
546
- };
547
- }
548
- updateLastTouch(tableName) {
549
- this.preAggregations.updateLastTouch(tableName).catch(e => {
550
- this.logger('Error on pre-aggregation touch', {
551
- error: (e.stack || e), preAggregation: this.preAggregation, requestId: this.requestId,
552
- });
553
- });
554
- }
555
- contentVersion(invalidationKeys) {
556
- const versionArray = [this.preAggregation.structureVersionLoadSql || this.preAggregation.loadSql];
557
- if (this.preAggregation.indexesSql && this.preAggregation.indexesSql.length) {
558
- versionArray.push(this.preAggregation.indexesSql);
559
- }
560
- if (this.preAggregation.streamOffset) {
561
- versionArray.push(this.preAggregation.streamOffset);
562
- }
563
- if (this.preAggregation.outputColumnTypes) {
564
- versionArray.push(this.preAggregation.outputColumnTypes);
565
- }
566
- versionArray.push(invalidationKeys);
567
- return version(versionArray);
568
- }
569
- priority(defaultValue) {
570
- return this.preAggregation.priority != null ? this.preAggregation.priority : defaultValue;
571
- }
572
- getInvalidationKeyValues() {
573
- return Promise.all((this.preAggregation.invalidateKeyQueries || []).map((sqlQuery) => this.loadCache.keyQueryResult(sqlQuery, this.waitForRenew, this.priority(10))));
574
- }
575
- getPartitionInvalidationKeyValues() {
576
- if (this.preAggregation.partitionInvalidateKeyQueries) {
577
- return Promise.all((this.preAggregation.partitionInvalidateKeyQueries || []).map((sqlQuery) => this.loadCache.keyQueryResult(sqlQuery, this.waitForRenew, this.priority(10))));
578
- }
579
- else {
580
- return this.getInvalidationKeyValues();
581
- }
582
- }
583
- scheduleRefresh(invalidationKeys, newVersionEntry) {
584
- this.logger('Refreshing pre-aggregation content', {
585
- preAggregation: this.preAggregation,
586
- requestId: this.requestId,
587
- queryKey: this.preAggregationQueryKey(invalidationKeys),
588
- newVersionEntry
589
- });
590
- this.executeInQueue(invalidationKeys, this.priority(0), newVersionEntry)
591
- .catch(e => {
592
- if (!(e instanceof ContinueWaitError_1.ContinueWaitError)) {
593
- this.logger('Error refreshing pre-aggregation', {
594
- error: (e.stack || e), preAggregation: this.preAggregation, requestId: this.requestId
595
- });
596
- }
597
- });
598
- }
599
- async executeInQueue(invalidationKeys, priority, newVersionEntry) {
600
- const queue = await this.preAggregations.getQueue(this.preAggregation.dataSource);
601
- return queue.executeInQueue('query', this.preAggregationQueryKey(invalidationKeys), {
602
- preAggregation: this.preAggregation,
603
- preAggregationsTablesToTempTables: this.preAggregationsTablesToTempTables,
604
- newVersionEntry,
605
- requestId: this.requestId,
606
- invalidationKeys,
607
- forceBuild: this.forceBuild,
608
- isJob: this.isJob,
609
- metadata: this.metadata,
610
- orphanedTimeout: this.orphanedTimeout,
611
- }, priority,
612
- // eslint-disable-next-line no-use-before-define
613
- { stageQueryKey: PreAggregations.preAggregationQueryCacheKey(this.preAggregation), requestId: this.requestId });
614
- }
615
- preAggregationQueryKey(invalidationKeys) {
616
- return this.preAggregation.indexesSql && this.preAggregation.indexesSql.length ?
617
- [this.preAggregation.loadSql, this.preAggregation.indexesSql, invalidationKeys] :
618
- [this.preAggregation.loadSql, invalidationKeys];
619
- }
620
- targetTableName(versionEntry) {
621
- // eslint-disable-next-line no-use-before-define
622
- return PreAggregations.targetTableName(versionEntry);
623
- }
624
- refresh(newVersionEntry, invalidationKeys, client) {
625
- this.updateLastTouch(this.targetTableName(newVersionEntry));
626
- let refreshStrategy = this.refreshStoreInSourceStrategy;
627
- if (this.preAggregation.external) {
628
- const readOnly = this.preAggregation.readOnly ||
629
- client.config && client.config.readOnly ||
630
- client.readOnly && (typeof client.readOnly === 'boolean' ? client.readOnly : client.readOnly());
631
- if (readOnly) {
632
- refreshStrategy = this.refreshReadOnlyExternalStrategy;
633
- }
634
- else {
635
- refreshStrategy = this.refreshWriteStrategy;
636
- }
637
- }
638
- return (0, base_driver_1.cancelCombinator)(saveCancelFn => refreshStrategy.bind(this)(client, newVersionEntry, saveCancelFn, invalidationKeys));
639
- }
640
- logExecutingSql(payload) {
641
- this.logger('Executing Load Pre Aggregation SQL', payload);
642
- }
643
- queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry) {
644
- return {
645
- queryKey: this.preAggregationQueryKey(invalidationKeys),
646
- query,
647
- values: params,
648
- targetTableName,
649
- requestId: this.requestId,
650
- newVersionEntry,
651
- buildRangeEnd: this.preAggregation.buildRangeEnd,
652
- };
653
- }
654
- async refreshStoreInSourceStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
655
- const [loadSql, params] = Array.isArray(this.preAggregation.loadSql) ? this.preAggregation.loadSql : [this.preAggregation.loadSql, []];
656
- const targetTableName = this.targetTableName(newVersionEntry);
657
- const query = QueryCache_1.QueryCache.replacePreAggregationTableNames(loadSql, this.preAggregationsTablesToTempTables).replace(this.preAggregation.tableName, targetTableName);
658
- const queryOptions = this.queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry);
659
- this.logExecutingSql(queryOptions);
660
- try {
661
- // TODO move index creation to the driver
662
- await saveCancelFn(client.loadPreAggregationIntoTable(targetTableName, query, params, {
663
- streamOffset: this.preAggregation.streamOffset,
664
- outputColumnTypes: this.preAggregation.outputColumnTypes,
665
- ...queryOptions
666
- }));
667
- await this.createIndexes(client, newVersionEntry, saveCancelFn, queryOptions);
668
- await this.loadCache.fetchTables(this.preAggregation);
669
- }
670
- finally {
671
- // We must clean orphaned in any cases: success or exception
672
- await this.dropOrphanedTables(client, targetTableName, saveCancelFn, false, queryOptions);
673
- await this.loadCache.fetchTables(this.preAggregation);
674
- }
675
- }
676
- async refreshWriteStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
677
- const capabilities = client?.capabilities();
678
- const withTempTable = !(capabilities?.unloadWithoutTempTable);
679
- const dropSourceTempTable = !capabilities?.streamingSource;
680
- return this.runWriteStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys, withTempTable, dropSourceTempTable);
681
- }
682
- /**
683
- * Runs export strategy with write access in data source
684
- */
685
- async runWriteStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys, withTempTable, dropSourceTempTable) {
686
- if (withTempTable) {
687
- await client.createSchemaIfNotExists(this.preAggregation.preAggregationsSchema);
688
- }
689
- const targetTableName = this.targetTableName(newVersionEntry);
690
- const queryOptions = await this.prepareWriteStrategy(client, targetTableName, newVersionEntry, saveCancelFn, invalidationKeys, withTempTable);
691
- try {
692
- const tableData = await this.downloadExternalPreAggregation(client, newVersionEntry, saveCancelFn, queryOptions, withTempTable);
693
- try {
694
- await this.uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn, queryOptions);
695
- }
696
- finally {
697
- if (tableData && tableData.release) {
698
- await tableData.release();
699
- }
700
- }
701
- }
702
- finally {
703
- await this.cleanupWriteStrategy(client, targetTableName, queryOptions, saveCancelFn, withTempTable, dropSourceTempTable);
704
- }
705
- }
706
- /**
707
- * Cleanup tables after write strategy
708
- */
709
- async cleanupWriteStrategy(client, targetTableName, queryOptions, saveCancelFn, withTempTable, dropSourceTempTable) {
710
- if (withTempTable && dropSourceTempTable) {
711
- await this.withDropLock(false, async () => {
712
- this.logger('Dropping source temp table', queryOptions);
713
- const actualTables = await client.getTablesQuery(this.preAggregation.preAggregationsSchema);
714
- const mappedActualTables = actualTables.map(t => `${this.preAggregation.preAggregationsSchema}.${t.table_name || t.TABLE_NAME}`);
715
- if (mappedActualTables.includes(targetTableName)) {
716
- await client.dropTable(targetTableName);
717
- }
718
- });
719
- }
720
- // We must clean orphaned in any cases: success or exception
721
- await this.loadCache.fetchTables(this.preAggregation);
722
- await this.dropOrphanedTables(client, targetTableName, saveCancelFn, false, queryOptions);
723
- }
724
- /**
725
- * Create table (if required) and prepares query options object
726
- */
727
- async prepareWriteStrategy(client, targetTableName, newVersionEntry, saveCancelFn, invalidationKeys, withTempTable) {
728
- if (withTempTable) {
729
- const [loadSql, params] = Array.isArray(this.preAggregation.loadSql) ? this.preAggregation.loadSql : [this.preAggregation.loadSql, []];
730
- const query = QueryCache_1.QueryCache.replacePreAggregationTableNames(loadSql, this.preAggregationsTablesToTempTables).replace(this.preAggregation.tableName, targetTableName);
731
- const queryOptions = this.queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry);
732
- this.logExecutingSql(queryOptions);
733
- await saveCancelFn(client.loadPreAggregationIntoTable(targetTableName, query, params, {
734
- streamOffset: this.preAggregation.streamOffset,
735
- outputColumnTypes: this.preAggregation.outputColumnTypes,
736
- ...queryOptions
737
- }));
738
- return queryOptions;
739
- }
740
- else {
741
- const [sql, params] = Array.isArray(this.preAggregation.sql) ? this.preAggregation.sql : [this.preAggregation.sql, []];
742
- const queryOptions = this.queryOptions(invalidationKeys, sql, params, targetTableName, newVersionEntry);
743
- this.logExecutingSql(queryOptions);
744
- return queryOptions;
745
- }
746
- }
747
- /**
748
- * Strategy to copy pre-aggregation from source db (for read-only permissions) to external data
749
- */
750
- async refreshReadOnlyExternalStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
751
- const [sql, params] = Array.isArray(this.preAggregation.sql) ? this.preAggregation.sql : [this.preAggregation.sql, []];
752
- const queryOptions = this.queryOptions(invalidationKeys, sql, params, this.targetTableName(newVersionEntry), newVersionEntry);
753
- this.logExecutingSql(queryOptions);
754
- this.logger('Downloading external pre-aggregation via query', queryOptions);
755
- const externalDriver = await this.externalDriverFactory();
756
- const capabilities = externalDriver.capabilities && externalDriver.capabilities();
757
- let tableData;
758
- if (capabilities.csvImport && client.unloadFromQuery && await client.isUnloadSupported(this.getUnloadOptions())) {
759
- tableData = await saveCancelFn(client.unloadFromQuery(sql, params, this.getUnloadOptions())).catch((error) => {
760
- this.logger('Downloading external pre-aggregation via query error', { ...queryOptions, error: error.stack || error.message });
761
- throw error;
762
- });
763
- }
764
- else {
765
- tableData = await saveCancelFn(client.downloadQueryResults(sql, params, {
766
- streamOffset: this.preAggregation.streamOffset,
767
- outputColumnTypes: this.preAggregation.outputColumnTypes,
768
- ...queryOptions,
769
- ...capabilities,
770
- ...this.getStreamingOptions(),
771
- })).catch((error) => {
772
- this.logger('Downloading external pre-aggregation via query error', { ...queryOptions, error: error.stack || error.message });
773
- throw error;
774
- });
775
- }
776
- this.logger('Downloading external pre-aggregation via query completed', {
777
- ...queryOptions,
778
- isUnloadSupported: (0, base_driver_1.isDownloadTableCSVData)(tableData)
779
- });
780
- try {
781
- await this.uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn, queryOptions);
782
- }
783
- finally {
784
- if (tableData.release) {
785
- await tableData.release();
786
- }
787
- }
788
- await this.loadCache.fetchTables(this.preAggregation);
789
- }
790
- getUnloadOptions() {
791
- return {
792
- // Default: 16mb for Snowflake, Should be specified in MBs, because drivers convert it
793
- maxFileSize: 64
794
- };
795
- }
796
- getStreamingOptions() {
797
- return {
798
- // Default: 16384 (16KB), or 16 for objectMode streams. PostgreSQL/MySQL use object streams
799
- highWaterMark: 10000
800
- };
801
- }
802
- /**
803
- * prepares download data for future cube store usage
804
- */
805
- async downloadExternalPreAggregation(client, newVersionEntry, saveCancelFn, queryOptions, withTempTable) {
806
- const table = this.targetTableName(newVersionEntry);
807
- this.logger('Downloading external pre-aggregation', queryOptions);
808
- try {
809
- const externalDriver = await this.externalDriverFactory();
810
- const capabilities = externalDriver.capabilities && externalDriver.capabilities();
811
- let tableData;
812
- if (withTempTable) {
813
- tableData = await this.getTableDataWithTempTable(client, table, saveCancelFn, queryOptions, capabilities);
814
- }
815
- else {
816
- tableData = await this.getTableDataWithoutTempTable(client, table, saveCancelFn, queryOptions, capabilities);
817
- }
818
- this.logger('Downloading external pre-aggregation completed', {
819
- ...queryOptions,
820
- isUnloadSupported: (0, base_driver_1.isDownloadTableCSVData)(tableData)
821
- });
822
- return tableData;
823
- }
824
- catch (error) {
825
- this.logger('Downloading external pre-aggregation error', {
826
- ...queryOptions,
827
- error: error?.stack || error?.message
828
- });
829
- throw error;
830
- }
831
- }
832
- /**
833
- * prepares download data when temp table = true
834
- */
835
- async getTableDataWithTempTable(client, table, saveCancelFn, queryOptions, externalDriverCapabilities) {
836
- let tableData;
837
- if (externalDriverCapabilities.csvImport && client.unload && await client.isUnloadSupported(this.getUnloadOptions())) {
838
- tableData = await saveCancelFn(client.unload(table, this.getUnloadOptions()));
839
- }
840
- else if (externalDriverCapabilities.streamImport && client.stream) {
841
- tableData = await saveCancelFn(client.stream(`SELECT * FROM ${table}`, [], this.getStreamingOptions()));
842
- if (client.unload) {
843
- const stream = new StreamObjectsCounter_1.LargeStreamWarning(this.preAggregation.preAggregationId, (msg) => {
844
- this.logger('Downloading external pre-aggregation warning', {
845
- ...queryOptions,
846
- error: msg
847
- });
848
- });
849
- tableData.rowStream.pipe(stream);
850
- tableData.rowStream = stream;
851
- }
852
- }
853
- else {
854
- tableData = await saveCancelFn(client.downloadTable(table, {
855
- streamOffset: this.preAggregation.streamOffset,
856
- outputColumnTypes: this.preAggregation.outputColumnTypes,
857
- ...externalDriverCapabilities
858
- }));
859
- }
860
- if (!tableData.types) {
861
- tableData.types = await saveCancelFn(client.tableColumnTypes(table));
862
- }
863
- return tableData;
864
- }
865
- /**
866
- * prepares download data when temp table = false
867
- */
868
- async getTableDataWithoutTempTable(client, table, saveCancelFn, queryOptions, externalDriverCapabilities) {
869
- const [sql, params] = Array.isArray(this.preAggregation.sql) ? this.preAggregation.sql : [this.preAggregation.sql, []];
870
- let tableData;
871
- if (externalDriverCapabilities.csvImport && client.unload && await client.isUnloadSupported(this.getUnloadOptions())) {
872
- return saveCancelFn(client.unload(table, { ...this.getUnloadOptions(), query: { sql, params } }));
873
- }
874
- else if (externalDriverCapabilities.streamImport && client.stream) {
875
- tableData = await saveCancelFn(client.stream(sql, params, this.getStreamingOptions()));
876
- if (client.unload) {
877
- const stream = new StreamObjectsCounter_1.LargeStreamWarning(this.preAggregation.preAggregationId, (msg) => {
878
- this.logger('Downloading external pre-aggregation warning', {
879
- ...queryOptions,
880
- error: msg
881
- });
882
- });
883
- tableData.rowStream.pipe(stream);
884
- tableData.rowStream = stream;
885
- }
886
- }
887
- else {
888
- tableData = { rows: await saveCancelFn(client.query(sql, params)) };
889
- }
890
- if (!tableData.types && client.queryColumnTypes) {
891
- tableData.types = await saveCancelFn(client.queryColumnTypes(sql, params));
892
- }
893
- return tableData;
894
- }
895
- async uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn, queryOptions) {
896
- const externalDriver = await this.externalDriverFactory();
897
- const table = this.targetTableName(newVersionEntry);
898
- this.logger('Uploading external pre-aggregation', queryOptions);
899
- await saveCancelFn(externalDriver.uploadTableWithIndexes(table, tableData.types, tableData, this.prepareIndexesSql(newVersionEntry, queryOptions), this.preAggregation.uniqueKeyColumns, queryOptions, {
900
- aggregationsColumns: this.preAggregation.aggregationsColumns,
901
- createTableIndexes: this.prepareCreateTableIndexes(newVersionEntry),
902
- sealAt: this.preAggregation.sealAt
903
- })).catch((error) => {
904
- this.logger('Uploading external pre-aggregation error', { ...queryOptions, error: error?.stack || error?.message });
905
- throw error;
906
- });
907
- this.logger('Uploading external pre-aggregation completed', queryOptions);
908
- await this.loadCache.fetchTables(this.preAggregation);
909
- await this.dropOrphanedTables(externalDriver, table, saveCancelFn, true, queryOptions);
910
- }
911
- async createIndexes(driver, newVersionEntry, saveCancelFn, queryOptions) {
912
- const indexesSql = this.prepareIndexesSql(newVersionEntry, queryOptions);
913
- for (let i = 0; i < indexesSql.length; i++) {
914
- const [query, params] = indexesSql[i].sql;
915
- await saveCancelFn(driver.query(query, params));
916
- }
917
- }
918
- prepareIndexesSql(newVersionEntry, queryOptions) {
919
- if (!this.preAggregation.indexesSql || !this.preAggregation.indexesSql.length) {
920
- return [];
921
- }
922
- return this.preAggregation.indexesSql.map(({ sql, indexName }) => {
923
- const [query, params] = sql;
924
- const indexVersionEntry = {
925
- ...newVersionEntry,
926
- table_name: indexName
927
- };
928
- this.logger('Creating pre-aggregation index', queryOptions);
929
- const resultingSql = QueryCache_1.QueryCache.replacePreAggregationTableNames(query, this.preAggregationsTablesToTempTables.concat([
930
- [this.preAggregation.tableName, { targetTableName: this.targetTableName(newVersionEntry) }],
931
- [indexName, { targetTableName: this.targetTableName(indexVersionEntry) }]
932
- ]));
933
- return { sql: [resultingSql, params] };
934
- });
935
- }
936
- prepareCreateTableIndexes(newVersionEntry) {
937
- if (!this.preAggregation.createTableIndexes || !this.preAggregation.createTableIndexes.length) {
938
- return [];
939
- }
940
- return this.preAggregation.createTableIndexes.map(({ indexName, type, columns }) => {
941
- const indexVersionEntry = {
942
- ...newVersionEntry,
943
- table_name: indexName
944
- };
945
- return { indexName: this.targetTableName(indexVersionEntry), type, columns };
946
- });
947
- }
948
- async withDropLock(external, lockFn) {
949
- const lockKey = this.dropLockKey(external);
950
- return this.queryCache.withLock(lockKey, 60 * 5, lockFn);
951
- }
952
- async dropOrphanedTables(client, justCreatedTable, saveCancelFn, external, queryOptions) {
953
- await this.preAggregations.addTableUsed(justCreatedTable);
954
- return this.withDropLock(external, async () => {
955
- this.logger('Dropping orphaned tables', { ...queryOptions, external });
956
- const actualTables = await client.getTablesQuery(this.preAggregation.preAggregationsSchema);
957
- const versionEntries = tablesToVersionEntries(this.preAggregation.preAggregationsSchema, actualTables);
958
- const versionEntriesToSave = ramda_1.default.pipe(ramda_1.default.groupBy(v => v.table_name), ramda_1.default.toPairs, ramda_1.default.map(p => p[1][0]))(versionEntries);
959
- const structureVersionsToSave = ramda_1.default.pipe(ramda_1.default.filter((v) => (new Date().getTime() - v.last_updated_at <
960
- this.structureVersionPersistTime * 1000)), ramda_1.default.groupBy(v => `${v.table_name}_${v.structure_version}`), ramda_1.default.toPairs, ramda_1.default.map(p => p[1][0]))(versionEntries);
961
- const refreshEndReached = await this.preAggregations.getRefreshEndReached();
962
- const toSave = this.preAggregations.dropPreAggregationsWithoutTouch && refreshEndReached
963
- ? (await this.preAggregations.tablesUsed())
964
- .concat(await this.preAggregations.tablesTouched())
965
- .concat([justCreatedTable])
966
- : (await this.preAggregations.tablesUsed())
967
- .concat(structureVersionsToSave.map(v => this.targetTableName(v)))
968
- .concat(versionEntriesToSave.map(v => this.targetTableName(v)))
969
- .concat([justCreatedTable]);
970
- const toDrop = actualTables
971
- .map(t => `${this.preAggregation.preAggregationsSchema}.${t.table_name || t.TABLE_NAME}`)
972
- .filter(t => toSave.indexOf(t) === -1);
973
- await Promise.all(toDrop.map(table => saveCancelFn(client.dropTable(table))));
974
- this.logger('Dropping orphaned tables completed', {
975
- ...queryOptions,
976
- external,
977
- tablesToDrop: JSON.stringify(toDrop),
978
- });
979
- });
980
- }
981
- dropLockKey(external) {
982
- return external
983
- ? 'drop-orphaned-tables-external'
984
- : `drop-orphaned-tables:${this.preAggregation.dataSource}`;
985
- }
986
- }
987
- exports.PreAggregationLoader = PreAggregationLoader;
988
- class PreAggregationPartitionRangeLoader {
989
- redisPrefix;
990
- driverFactory;
991
- logger;
992
- queryCache;
993
- preAggregations;
994
- preAggregation;
995
- preAggregationsTablesToTempTables;
996
- loadCache;
997
- options;
998
- /**
999
- * Determines whether current instance instantiated for a jobed build query
1000
- * (initialized by the /cubejs-system/v1/pre-aggregations/jobs endpoint) or
1001
- * not.
1002
- */
1003
- isJob;
1004
- waitForRenew;
1005
- requestId;
1006
- lambdaQuery;
1007
- dataSource;
1008
- compilerCacheFn;
1009
- constructor(redisPrefix, driverFactory, logger, queryCache,
1010
- // eslint-disable-next-line no-use-before-define
1011
- preAggregations, preAggregation, preAggregationsTablesToTempTables, loadCache, options = {
1012
- maxPartitions: 10000,
1013
- maxSourceRowLimit: 10000,
1014
- }) {
1015
- this.redisPrefix = redisPrefix;
1016
- this.driverFactory = driverFactory;
1017
- this.logger = logger;
1018
- this.queryCache = queryCache;
1019
- this.preAggregations = preAggregations;
1020
- this.preAggregation = preAggregation;
1021
- this.preAggregationsTablesToTempTables = preAggregationsTablesToTempTables;
1022
- this.loadCache = loadCache;
1023
- this.options = options;
1024
- this.isJob = !!options.isJob;
1025
- this.waitForRenew = options.waitForRenew;
1026
- this.requestId = options.requestId;
1027
- this.lambdaQuery = options.lambdaQuery;
1028
- this.dataSource = preAggregation.dataSource;
1029
- this.compilerCacheFn = options.compilerCacheFn || ((subKey, cacheFn) => cacheFn());
1030
- }
1031
- async loadRangeQuery(rangeQuery, partitionRange) {
1032
- const [query, values, queryOptions] = rangeQuery;
1033
- const invalidate = this.preAggregation.invalidateKeyQueries &&
1034
- this.preAggregation.invalidateKeyQueries[0]
1035
- ? this.preAggregation.invalidateKeyQueries[0].slice(0, 2)
1036
- : false;
1037
- return this.queryCache.cacheQueryResult(query, values, QueryCache_1.QueryCache.queryCacheKey({
1038
- query,
1039
- values: values,
1040
- invalidate,
1041
- }), 24 * 60 * 60, {
1042
- renewalThreshold: this.queryCache.options.refreshKeyRenewalThreshold
1043
- || queryOptions?.renewalThreshold || 24 * 60 * 60,
1044
- waitForRenew: this.waitForRenew,
1045
- priority: this.priority(10),
1046
- requestId: this.requestId,
1047
- dataSource: this.dataSource,
1048
- useInMemory: true,
1049
- external: queryOptions?.external,
1050
- renewalKey: partitionRange ? await this.getInvalidationKeyValues(partitionRange) : null,
1051
- });
1052
- }
1053
- getInvalidationKeyValues(range) {
1054
- const partitionTableName = PreAggregationPartitionRangeLoader.partitionTableName(this.preAggregation.tableName, this.preAggregation.partitionGranularity, range);
1055
- return Promise.all((this.preAggregation.invalidateKeyQueries || []).map((sqlQuery) => (this.loadCache.keyQueryResult(this.replacePartitionSqlAndParams(sqlQuery, range, partitionTableName), this.waitForRenew, this.priority(10)))));
1056
- }
1057
- priority(defaultValue) {
1058
- return this.preAggregation.priority != null ? this.preAggregation.priority : defaultValue;
1059
- }
1060
- async replaceQueryBuildRangeParams(queryValues) {
1061
- if (queryValues?.find(p => p === shared_1.BUILD_RANGE_START_LOCAL || p === shared_1.BUILD_RANGE_END_LOCAL)) {
1062
- const [buildRangeStart, buildRangeEnd] = await this.loadBuildRange();
1063
- return queryValues?.map(param => {
1064
- if (param === shared_1.BUILD_RANGE_START_LOCAL) {
1065
- return (0, shared_1.utcToLocalTimeZone)(this.preAggregation.timezone, this.preAggregation.timestampFormat, buildRangeStart);
1066
- }
1067
- else if (param === shared_1.BUILD_RANGE_END_LOCAL) {
1068
- return (0, shared_1.utcToLocalTimeZone)(this.preAggregation.timezone, this.preAggregation.timestampFormat, buildRangeEnd);
1069
- }
1070
- else {
1071
- return param;
1072
- }
1073
- });
1074
- }
1075
- return null;
1076
- }
1077
- replacePartitionSqlAndParams(query, dateRange, partitionTableName) {
1078
- const [sql, params, options] = query;
1079
- const updateWindowToBoundary = options?.incremental && (0, shared_1.addSecondsToLocalTimestamp)(dateRange[1], this.preAggregation.timezone, options?.updateWindowSeconds || 0);
1080
- return [sql.replace(this.preAggregation.tableName, partitionTableName), params?.map(param => {
1081
- if (dateRange && param === shared_1.FROM_PARTITION_RANGE) {
1082
- return PreAggregationPartitionRangeLoader.inDbTimeZone(this.preAggregation, dateRange[0]);
1083
- }
1084
- else if (dateRange && param === shared_1.TO_PARTITION_RANGE) {
1085
- return PreAggregationPartitionRangeLoader.inDbTimeZone(this.preAggregation, dateRange[1]);
1086
- }
1087
- else {
1088
- return param;
1089
- }
1090
- }), {
1091
- ...options,
1092
- renewalThreshold: options?.incremental && updateWindowToBoundary < new Date() ?
1093
- // if updateWindowToBoundary passed just moments ago we want to renew it earlier in case
1094
- // of server and db clock don't match
1095
- Math.min(Math.round((new Date().getTime() - updateWindowToBoundary.getTime()) / 1000), options?.renewalThresholdOutsideUpdateWindow) :
1096
- options?.renewalThreshold
1097
- }];
1098
- }
1099
- partitionPreAggregationDescription(range, buildRange) {
1100
- const partitionTableName = PreAggregationPartitionRangeLoader.partitionTableName(this.preAggregation.tableName, this.preAggregation.partitionGranularity, range);
1101
- const [_, buildRangeEnd] = buildRange;
1102
- const loadRange = [...range];
1103
- const partitionInvalidateKeyQueries = this.preAggregation.partitionInvalidateKeyQueries || this.preAggregation.invalidateKeyQueries;
1104
- // `partitionInvalidateKeyQueries = []` in case of real time
1105
- if ((!partitionInvalidateKeyQueries || partitionInvalidateKeyQueries.length > 0) && buildRangeEnd < range[1]) {
1106
- loadRange[1] = buildRangeEnd;
1107
- }
1108
- const sealAt = (0, shared_1.addSecondsToLocalTimestamp)(loadRange[1], this.preAggregation.timezone, this.preAggregation.updateWindowSeconds || 0).toISOString();
1109
- return {
1110
- ...this.preAggregation,
1111
- tableName: partitionTableName,
1112
- structureVersionLoadSql: this.preAggregation.loadSql &&
1113
- this.replacePartitionSqlAndParams(this.preAggregation.loadSql, range, partitionTableName),
1114
- loadSql: this.preAggregation.loadSql &&
1115
- this.replacePartitionSqlAndParams(this.preAggregation.loadSql, loadRange, partitionTableName),
1116
- sql: this.preAggregation.sql &&
1117
- this.replacePartitionSqlAndParams(this.preAggregation.sql, loadRange, partitionTableName),
1118
- invalidateKeyQueries: (this.preAggregation.invalidateKeyQueries || [])
1119
- .map(q => this.replacePartitionSqlAndParams(q, range, partitionTableName)),
1120
- partitionInvalidateKeyQueries: this.preAggregation.partitionInvalidateKeyQueries &&
1121
- this.preAggregation.partitionInvalidateKeyQueries.map(q => this.replacePartitionSqlAndParams(q, range, partitionTableName)),
1122
- indexesSql: (this.preAggregation.indexesSql || [])
1123
- .map(q => ({ ...q, sql: this.replacePartitionSqlAndParams(q.sql, range, partitionTableName) })),
1124
- previewSql: this.preAggregation.previewSql &&
1125
- this.replacePartitionSqlAndParams(this.preAggregation.previewSql, range, partitionTableName),
1126
- buildRangeStart: loadRange[0],
1127
- buildRangeEnd: loadRange[1],
1128
- sealAt, // Used only for kSql pre aggregations
1129
- };
1130
- }
1131
- async loadPreAggregations() {
1132
- if (this.preAggregation.partitionGranularity && !this.preAggregation.expandedPartition) {
1133
- const loadPreAggregationsByPartitionRanges = async ({ buildRange, partitionRanges }) => {
1134
- 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));
1135
- const resolveResults = await Promise.all(partitionLoaders.map(async (l, i) => {
1136
- const result = await l.loadPreAggregation(false);
1137
- return result && {
1138
- ...result,
1139
- partitionRange: partitionRanges[i]
1140
- };
1141
- }));
1142
- return { loadResults: resolveResults.filter(res => res !== null), partitionLoaders };
1143
- };
1144
- // eslint-disable-next-line prefer-const
1145
- let loadResultAndLoaders = await loadPreAggregationsByPartitionRanges(await this.partitionRanges());
1146
- if (this.options.externalRefresh && loadResultAndLoaders.loadResults.length === 0) {
1147
- loadResultAndLoaders = await loadPreAggregationsByPartitionRanges(await this.partitionRanges(true));
1148
- // In case there're no partitions ready at matched time dimension intersection then no data can be retrieved.
1149
- // We need to provide any table so query can just execute successfully.
1150
- if (loadResultAndLoaders.loadResults.length > 0) {
1151
- loadResultAndLoaders.loadResults = [loadResultAndLoaders.loadResults[loadResultAndLoaders.loadResults.length - 1]];
1152
- }
1153
- }
1154
- if (this.options.externalRefresh && loadResultAndLoaders.loadResults.length === 0) {
1155
- throw new Error(
1156
- // eslint-disable-next-line no-use-before-define
1157
- PreAggregations.noPreAggregationPartitionsBuiltMessage(loadResultAndLoaders.partitionLoaders.map(p => p.preAggregation)));
1158
- }
1159
- let { loadResults } = loadResultAndLoaders;
1160
- let lambdaTable;
1161
- let emptyResult = false;
1162
- if (this.preAggregation.rollupLambdaId) {
1163
- if (this.lambdaQuery && loadResults.length > 0) {
1164
- const { buildRangeEnd, targetTableName } = loadResults[loadResults.length - 1];
1165
- const lambdaTypes = await this.loadCache.getTableColumnTypes(this.preAggregation, targetTableName);
1166
- lambdaTable = await this.downloadLambdaTable(buildRangeEnd, lambdaTypes);
1167
- }
1168
- const rollupLambdaResults = this.preAggregationsTablesToTempTables.filter(tempTableResult => tempTableResult[1].rollupLambdaId === this.preAggregation.rollupLambdaId);
1169
- const filteredResults = loadResults.filter(r => (this.preAggregation.lastRollupLambda || (0, shared_1.reformatInIsoLocal)(r.buildRangeEnd) === (0, shared_1.reformatInIsoLocal)(r.partitionRange[1])) &&
1170
- rollupLambdaResults.every(result => !result[1].buildRangeEnd || (0, shared_1.reformatInIsoLocal)(result[1].buildRangeEnd) < (0, shared_1.reformatInIsoLocal)(r.partitionRange[0])));
1171
- if (filteredResults.length === 0) {
1172
- emptyResult = true;
1173
- loadResults = [loadResults[loadResults.length - 1]];
1174
- }
1175
- else {
1176
- loadResults = filteredResults;
1177
- }
1178
- }
1179
- const allTableTargetNames = loadResults.map(targetTableName => targetTableName.targetTableName);
1180
- let lastUpdatedAt = getLastUpdatedAtTimestamp(loadResults.map(r => r.lastUpdatedAt));
1181
- if (lambdaTable) {
1182
- allTableTargetNames.push(lambdaTable.name);
1183
- lastUpdatedAt = Date.now();
1184
- }
1185
- const unionTargetTableName = allTableTargetNames
1186
- .map(targetTableName => `SELECT * FROM ${targetTableName}${emptyResult ? ' WHERE 1 = 0' : ''}`)
1187
- .join(' UNION ALL ');
1188
- return {
1189
- targetTableName: allTableTargetNames.length === 1 && !emptyResult ? allTableTargetNames[0] : `(${unionTargetTableName})`,
1190
- refreshKeyValues: loadResults.map(t => t.refreshKeyValues),
1191
- lastUpdatedAt,
1192
- buildRangeEnd: !emptyResult && loadResults.length && loadResults[loadResults.length - 1].buildRangeEnd,
1193
- lambdaTable,
1194
- rollupLambdaId: this.preAggregation.rollupLambdaId,
1195
- };
1196
- }
1197
- else {
1198
- return new PreAggregationLoader(this.redisPrefix, this.driverFactory, this.logger, this.queryCache, this.preAggregations, this.preAggregation, this.preAggregationsTablesToTempTables, this.loadCache, this.options).loadPreAggregation(true);
1199
- }
1200
- }
1201
- /**
1202
- * Downloads the lambda table from the source DB.
1203
- */
1204
- async downloadLambdaTable(fromDate, lambdaTypes) {
1205
- const { sqlAndParams, cacheKeyQueries } = this.lambdaQuery;
1206
- const [query, params] = sqlAndParams;
1207
- const values = params.map((p) => {
1208
- if (p === shared_1.FROM_PARTITION_RANGE) {
1209
- return fromDate;
1210
- }
1211
- if (p === shared_1.MAX_SOURCE_ROW_LIMIT) {
1212
- return this.options.maxSourceRowLimit;
1213
- }
1214
- return p;
1215
- });
1216
- const { data } = await this.queryCache.renewQuery(query, values, cacheKeyQueries, 60 * 60, [query, values], undefined, {
1217
- requestId: this.requestId,
1218
- skipRefreshKeyWaitForRenew: false,
1219
- dataSource: this.dataSource,
1220
- external: false,
1221
- useCsvQuery: true,
1222
- lambdaTypes,
1223
- });
1224
- if (data.rowCount === this.options.maxSourceRowLimit) {
1225
- throw new Error(`The maximum number of source rows ${this.options.maxSourceRowLimit} was reached for ${this.preAggregation.preAggregationId}`);
1226
- }
1227
- return {
1228
- name: `${exports.LAMBDA_TABLE_PREFIX}_${this.preAggregation.tableName.replace('.', '_')}`,
1229
- columns: data.types,
1230
- csvRows: data.csvRows,
1231
- };
1232
- }
1233
- async partitionPreAggregations() {
1234
- if (this.preAggregation.partitionGranularity && !this.preAggregation.expandedPartition) {
1235
- const { buildRange, partitionRanges } = await this.partitionRanges();
1236
- return this.compilerCacheFn(['partitions', JSON.stringify(buildRange)], () => partitionRanges.map(range => this.partitionPreAggregationDescription(range, buildRange)));
1237
- }
1238
- else {
1239
- return [this.preAggregation];
1240
- }
1241
- }
1242
- async partitionRanges(ignoreMatchedDateRange) {
1243
- const buildRange = await this.loadBuildRange();
1244
- if (!buildRange[0] || !buildRange[1]) {
1245
- return { buildRange, partitionRanges: [] };
1246
- }
1247
- let dateRange = PreAggregationPartitionRangeLoader.intersectDateRanges(buildRange, ignoreMatchedDateRange ? undefined : this.preAggregation.matchedTimeDimensionDateRange);
1248
- if (!dateRange) {
1249
- // If there's no date range intersection between query data range and pre-aggregation build range
1250
- // use last partition so outer query can receive expected table structure.
1251
- dateRange = [buildRange[1], buildRange[1]];
1252
- }
1253
- const partitionRanges = this.compilerCacheFn(['timeSeries', this.preAggregation.partitionGranularity, JSON.stringify(dateRange), `${this.preAggregation.timestampPrecision}`], () => PreAggregationPartitionRangeLoader.timeSeries(this.preAggregation.partitionGranularity, dateRange, this.preAggregation.timestampPrecision));
1254
- if (partitionRanges.length > this.options.maxPartitions) {
1255
- throw new Error(`Pre-aggregation '${this.preAggregation.tableName}' requested to build ${partitionRanges.length} partitions which exceeds the maximum number of partitions per pre-aggregation of ${this.options.maxPartitions}`);
1256
- }
1257
- return { buildRange: dateRange, partitionRanges };
1258
- }
1259
- async loadBuildRange() {
1260
- const { preAggregationStartEndQueries } = this.preAggregation;
1261
- const [startDate, endDate] = await Promise.all(preAggregationStartEndQueries.map(async (rangeQuery) => PreAggregationPartitionRangeLoader.extractDate(await this.loadRangeQuery(rangeQuery))));
1262
- if (!this.preAggregation.partitionGranularity) {
1263
- return this.orNowIfEmpty([startDate, endDate]);
1264
- }
1265
- const wholeSeriesRanges = PreAggregationPartitionRangeLoader.timeSeries(this.preAggregation.partitionGranularity, this.orNowIfEmpty([startDate, endDate]), this.preAggregation.timestampPrecision);
1266
- 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]))));
1267
- return this.orNowIfEmpty([rangeStart, rangeEnd]);
1268
- }
1269
- now() {
1270
- return (0, shared_1.utcToLocalTimeZone)(this.preAggregation.timezone, 'YYYY-MM-DDTHH:mm:ss.SSS', new Date().toJSON().substring(0, 23));
1271
- }
1272
- orNowIfEmpty(dateRange) {
1273
- if (!dateRange[0] && !dateRange[1]) {
1274
- const now = this.now();
1275
- return [now, now];
1276
- }
1277
- if (!dateRange[0]) {
1278
- return [dateRange[1], dateRange[1]];
1279
- }
1280
- if (!dateRange[1]) {
1281
- return [dateRange[0], dateRange[0]];
1282
- }
1283
- return dateRange;
1284
- }
1285
- static checkDataRangeType(range) {
1286
- if (!range) {
1287
- return;
1288
- }
1289
- if (range.length !== 2) {
1290
- throw new Error(`Date range expected to be an array with 2 elements but ${range} found`);
1291
- }
1292
- if (typeof range[0] !== 'string' || typeof range[1] !== 'string') {
1293
- throw new Error(`Date range expected to be a string array but ${range} found`);
1294
- }
1295
- if ((range[0].length !== 23 && range[0].length !== 26) || (range[1].length !== 23 && range[0].length !== 26)) {
1296
- throw new Error(`Date range expected to be in YYYY-MM-DDTHH:mm:ss.SSS format but ${range} found`);
1297
- }
1298
- }
1299
- static intersectDateRanges(rangeA, rangeB) {
1300
- PreAggregationPartitionRangeLoader.checkDataRangeType(rangeA);
1301
- PreAggregationPartitionRangeLoader.checkDataRangeType(rangeB);
1302
- if (!rangeB) {
1303
- return rangeA;
1304
- }
1305
- if (!rangeA) {
1306
- return rangeB;
1307
- }
1308
- const from = rangeA[0] > rangeB[0] ? rangeA[0] : rangeB[0];
1309
- const to = rangeA[1] < rangeB[1] ? rangeA[1] : rangeB[1];
1310
- if (from > to) {
1311
- return null;
1312
- }
1313
- return [
1314
- from,
1315
- to,
1316
- ];
1317
- }
1318
- static timeSeries(granularity, dateRange, timestampPrecision) {
1319
- return (0, shared_1.timeSeries)(granularity, dateRange, {
1320
- timestampPrecision
1321
- });
1322
- }
1323
- static partitionTableName(tableName, partitionGranularity, dateRange) {
1324
- const partitionSuffix = dateRange[0].substring(0, partitionGranularity === 'hour' ? 13 : 10).replace(/[-T:]/g, '');
1325
- return `${tableName}${partitionSuffix}`;
1326
- }
1327
- static inDbTimeZone(preAggregationDescription, timestamp) {
1328
- return (0, shared_1.inDbTimeZone)(preAggregationDescription.timezone, preAggregationDescription.timestampFormat, timestamp);
1329
- }
1330
- static extractDate(data) {
1331
- return (0, shared_1.extractDate)(data);
1332
- }
1333
- static FROM_PARTITION_RANGE = shared_1.FROM_PARTITION_RANGE;
1334
- static TO_PARTITION_RANGE = shared_1.TO_PARTITION_RANGE;
1335
- }
1336
- exports.PreAggregationPartitionRangeLoader = PreAggregationPartitionRangeLoader;
93
+ exports.tablesToVersionEntries = tablesToVersionEntries;
1337
94
  class PreAggregations {
1338
95
  redisPrefix;
1339
96
  driverFactory;
@@ -1417,7 +174,7 @@ class PreAggregations {
1417
174
  */
1418
175
  async isPartitionExist(request, external, dataSource = 'default', schema, table, key, token) {
1419
176
  // fetching tables
1420
- const loadCache = new PreAggregationLoadCache(this.redisPrefix, () => this.driverFactory(dataSource), this.queryCache, this, {
177
+ const loadCache = new PreAggregationLoadCache_1.PreAggregationLoadCache(() => this.driverFactory(dataSource), this.queryCache, this, {
1421
178
  requestId: request,
1422
179
  dataSource,
1423
180
  tablePrefixes: external ? null : [schema],
@@ -1465,7 +222,7 @@ class PreAggregations {
1465
222
  const getLoadCacheByDataSource = (dataSource = 'default', preAggregationSchema) => {
1466
223
  if (!loadCacheByDataSource[`${dataSource}_${preAggregationSchema}`]) {
1467
224
  loadCacheByDataSource[`${dataSource}_${preAggregationSchema}`] =
1468
- new PreAggregationLoadCache(this.redisPrefix, () => this.driverFactory(dataSource), this.queryCache, this, {
225
+ new PreAggregationLoadCache_1.PreAggregationLoadCache(() => this.driverFactory(dataSource), this.queryCache, this, {
1469
226
  requestId: queryBody.requestId,
1470
227
  dataSource,
1471
228
  tablePrefixes:
@@ -1480,7 +237,7 @@ class PreAggregations {
1480
237
  };
1481
238
  let queryParamsReplacement = null;
1482
239
  const preAggregationsTablesToTempTablesPromise = preAggregations.map((p, i) => (preAggregationsTablesToTempTables) => {
1483
- const loader = new PreAggregationPartitionRangeLoader(this.redisPrefix, () => this.driverFactory(p.dataSource || 'default'), this.logger, this.queryCache, this, p, preAggregationsTablesToTempTables, getLoadCacheByDataSource(p.dataSource, p.preAggregationsSchema), {
240
+ const loader = new PreAggregationPartitionRangeLoader_1.PreAggregationPartitionRangeLoader(() => this.driverFactory(p.dataSource || 'default'), this.logger, this.queryCache, this, p, preAggregationsTablesToTempTables, getLoadCacheByDataSource(p.dataSource, p.preAggregationsSchema), {
1484
241
  maxPartitions: this.options.maxPartitions,
1485
242
  maxSourceRowLimit: this.options.maxSourceRowLimit,
1486
243
  isJob: queryBody.isJob,
@@ -1544,7 +301,7 @@ class PreAggregations {
1544
301
  const getLoadCacheByDataSource = (dataSource = 'default', preAggregationSchema) => {
1545
302
  if (!loadCacheByDataSource[`${dataSource}_${preAggregationSchema}`]) {
1546
303
  loadCacheByDataSource[`${dataSource}_${preAggregationSchema}`] =
1547
- new PreAggregationLoadCache(this.redisPrefix, () => this.driverFactory(dataSource), this.queryCache, this, {
304
+ new PreAggregationLoadCache_1.PreAggregationLoadCache(() => this.driverFactory(dataSource), this.queryCache, this, {
1548
305
  requestId: queryBody.requestId,
1549
306
  dataSource,
1550
307
  });
@@ -1552,7 +309,7 @@ class PreAggregations {
1552
309
  return loadCacheByDataSource[`${dataSource}_${preAggregationSchema}`];
1553
310
  };
1554
311
  const expandedPreAggregations = await Promise.all(preAggregations.map(p => {
1555
- const loader = new PreAggregationPartitionRangeLoader(this.redisPrefix, () => this.driverFactory(p.dataSource || 'default'), this.logger, this.queryCache, this, p, [], getLoadCacheByDataSource(p.dataSource, p.preAggregationsSchema), {
312
+ const loader = new PreAggregationPartitionRangeLoader_1.PreAggregationPartitionRangeLoader(() => this.driverFactory(p.dataSource || 'default'), this.logger, this.queryCache, this, p, [], getLoadCacheByDataSource(p.dataSource, p.preAggregationsSchema), {
1556
313
  maxPartitions: this.options.maxPartitions,
1557
314
  maxSourceRowLimit: this.options.maxSourceRowLimit,
1558
315
  waitForRenew: queryBody.renewQuery,
@@ -1577,7 +334,7 @@ class PreAggregations {
1577
334
  if (!this.queue[dataSource]) {
1578
335
  this.queue[dataSource] = QueryCache_1.QueryCache.createQueue(`SQL_PRE_AGGREGATIONS_${this.redisPrefix}_${dataSource}`, () => this.driverFactory(dataSource), (client, q) => {
1579
336
  const { preAggregation, preAggregationsTablesToTempTables, newVersionEntry, requestId, invalidationKeys, buildRangeEnd } = q;
1580
- 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, {
337
+ const loader = new PreAggregationLoader_1.PreAggregationLoader(() => this.driverFactory(dataSource), this.logger, this.queryCache, this, preAggregation, preAggregationsTablesToTempTables, new PreAggregationLoadCache_1.PreAggregationLoadCache(() => this.driverFactory(dataSource), this.queryCache, this, {
1581
338
  requestId,
1582
339
  dataSource,
1583
340
  }), { requestId, externalRefresh: this.externalRefresh, buildRangeEnd });
@@ -1608,7 +365,7 @@ class PreAggregations {
1608
365
  // eslint-disable-next-line @typescript-eslint/no-empty-function
1609
366
  () => ({}), (_, q) => {
1610
367
  const { preAggregation, requestId } = q;
1611
- const loadCache = new PreAggregationLoadCache(this.redisPrefix, () => this.driverFactory(dataSource), this.queryCache, this, {
368
+ const loadCache = new PreAggregationLoadCache_1.PreAggregationLoadCache(() => this.driverFactory(dataSource), this.queryCache, this, {
1612
369
  requestId,
1613
370
  dataSource,
1614
371
  });
@@ -1655,7 +412,7 @@ class PreAggregations {
1655
412
  const getLoadCacheByDataSource = (dataSource = 'default', preAggregationSchema) => {
1656
413
  if (!loadCacheByDataSource[`${dataSource}_${preAggregationSchema}`]) {
1657
414
  loadCacheByDataSource[`${dataSource}_${preAggregationSchema}`] =
1658
- new PreAggregationLoadCache(this.redisPrefix, () => this.driverFactory(dataSource), this.queryCache, this, {
415
+ new PreAggregationLoadCache_1.PreAggregationLoadCache(() => this.driverFactory(dataSource), this.queryCache, this, {
1659
416
  requestId,
1660
417
  dataSource,
1661
418
  });
@@ -1677,8 +434,7 @@ class PreAggregations {
1677
434
  }
1678
435
  async getQueueState(dataSource) {
1679
436
  const queue = await this.getQueue(dataSource);
1680
- const queries = await queue.getQueries();
1681
- return queries;
437
+ return queue.getQueries();
1682
438
  }
1683
439
  async cancelQueriesFromQueue(queryKeys, dataSource) {
1684
440
  const queue = await this.getQueue(dataSource);