@cubejs-backend/query-orchestrator 1.2.13 → 1.2.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/orchestrator/PreAggregationLoadCache.d.ts +42 -0
- package/dist/src/orchestrator/PreAggregationLoadCache.d.ts.map +1 -0
- package/dist/src/orchestrator/PreAggregationLoadCache.js +172 -0
- package/dist/src/orchestrator/PreAggregationLoadCache.js.map +1 -0
- package/dist/src/orchestrator/PreAggregationLoader.d.ts +105 -0
- package/dist/src/orchestrator/PreAggregationLoader.d.ts.map +1 -0
- package/dist/src/orchestrator/PreAggregationLoader.js +742 -0
- package/dist/src/orchestrator/PreAggregationLoader.js.map +1 -0
- package/dist/src/orchestrator/PreAggregationPartitionRangeLoader.d.ts +65 -0
- package/dist/src/orchestrator/PreAggregationPartitionRangeLoader.d.ts.map +1 -0
- package/dist/src/orchestrator/PreAggregationPartitionRangeLoader.js +355 -0
- package/dist/src/orchestrator/PreAggregationPartitionRangeLoader.js.map +1 -0
- package/dist/src/orchestrator/PreAggregations.d.ts +35 -223
- package/dist/src/orchestrator/PreAggregations.d.ts.map +1 -1
- package/dist/src/orchestrator/PreAggregations.js +17 -1261
- package/dist/src/orchestrator/PreAggregations.js.map +1 -1
- package/dist/src/orchestrator/QueryCache.d.ts +14 -4
- package/dist/src/orchestrator/QueryCache.d.ts.map +1 -1
- package/dist/src/orchestrator/QueryCache.js +1 -1
- package/dist/src/orchestrator/QueryCache.js.map +1 -1
- package/dist/src/orchestrator/QueryQueue.js +1 -1
- package/dist/src/orchestrator/QueryQueue.js.map +1 -1
- package/dist/src/orchestrator/index.d.ts +3 -0
- package/dist/src/orchestrator/index.d.ts.map +1 -1
- package/dist/src/orchestrator/index.js +3 -0
- package/dist/src/orchestrator/index.js.map +1 -1
- package/package.json +6 -6
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PreAggregationLoader = void 0;
|
|
7
|
+
const ramda_1 = __importDefault(require("ramda"));
|
|
8
|
+
const shared_1 = require("@cubejs-backend/shared");
|
|
9
|
+
const base_driver_1 = require("@cubejs-backend/base-driver");
|
|
10
|
+
const QueryCache_1 = require("./QueryCache");
|
|
11
|
+
const ContinueWaitError_1 = require("./ContinueWaitError");
|
|
12
|
+
const StreamObjectsCounter_1 = require("./StreamObjectsCounter");
|
|
13
|
+
const PreAggregations_1 = require("./PreAggregations");
|
|
14
|
+
// There are community developed and custom drivers which not always up-to-date with latest BaseDriver.
|
|
15
|
+
// Extra defence for drivers that don't expose now() yet.
|
|
16
|
+
function nowTimestamp(client) {
|
|
17
|
+
return client.nowTimestamp?.() ?? new Date().getTime();
|
|
18
|
+
}
|
|
19
|
+
class PreAggregationLoader {
|
|
20
|
+
driverFactory;
|
|
21
|
+
logger;
|
|
22
|
+
queryCache;
|
|
23
|
+
loadCache;
|
|
24
|
+
preAggregations;
|
|
25
|
+
preAggregation;
|
|
26
|
+
preAggregationsTablesToTempTables;
|
|
27
|
+
/**
|
|
28
|
+
* Determines whether current instance instantiated for a jobbed build query
|
|
29
|
+
* (initialized by the /cubejs-system/v1/pre-aggregations/jobs endpoint) or
|
|
30
|
+
* not.
|
|
31
|
+
*/
|
|
32
|
+
isJob;
|
|
33
|
+
waitForRenew;
|
|
34
|
+
forceBuild;
|
|
35
|
+
orphanedTimeout;
|
|
36
|
+
externalDriverFactory;
|
|
37
|
+
requestId;
|
|
38
|
+
metadata;
|
|
39
|
+
structureVersionPersistTime;
|
|
40
|
+
externalRefresh;
|
|
41
|
+
constructor(driverFactory, logger, queryCache, preAggregations, preAggregation, preAggregationsTablesToTempTables, loadCache, options = {}) {
|
|
42
|
+
this.driverFactory = driverFactory;
|
|
43
|
+
this.logger = logger;
|
|
44
|
+
this.queryCache = queryCache;
|
|
45
|
+
this.loadCache = loadCache;
|
|
46
|
+
this.preAggregations = preAggregations;
|
|
47
|
+
this.preAggregation = preAggregation;
|
|
48
|
+
this.preAggregationsTablesToTempTables = preAggregationsTablesToTempTables;
|
|
49
|
+
this.isJob = !!options.isJob;
|
|
50
|
+
this.waitForRenew = options.waitForRenew;
|
|
51
|
+
this.forceBuild = options.forceBuild;
|
|
52
|
+
this.orphanedTimeout = options.orphanedTimeout;
|
|
53
|
+
this.externalDriverFactory = preAggregations.externalDriverFactory;
|
|
54
|
+
this.requestId = options.requestId;
|
|
55
|
+
this.metadata = options.metadata;
|
|
56
|
+
this.structureVersionPersistTime = preAggregations.structureVersionPersistTime;
|
|
57
|
+
this.externalRefresh = options.externalRefresh;
|
|
58
|
+
if (this.externalRefresh && this.waitForRenew) {
|
|
59
|
+
const message = 'Invalid configuration - when externalRefresh is true, it will not perform a renew, therefore you cannot wait for it using waitForRenew.';
|
|
60
|
+
if (['production', 'test'].includes((0, shared_1.getEnv)('nodeEnv'))) {
|
|
61
|
+
throw new Error(message);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
this.logger('Invalid Configuration', {
|
|
65
|
+
requestId: this.requestId,
|
|
66
|
+
warning: message,
|
|
67
|
+
});
|
|
68
|
+
this.waitForRenew = false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async loadPreAggregation(throwOnMissingPartition) {
|
|
73
|
+
const notLoadedKey = (this.preAggregation.invalidateKeyQueries || [])
|
|
74
|
+
.find(keyQuery => !this.loadCache.hasKeyQueryResult(keyQuery));
|
|
75
|
+
if (this.isJob || !(notLoadedKey && !this.waitForRenew)) {
|
|
76
|
+
// Case 1: pre-agg build job processing.
|
|
77
|
+
// Case 2: either we have no data cached for this rollup or waitForRenew
|
|
78
|
+
// is true, either way, synchronously renew what data is needed so that
|
|
79
|
+
// the most current data will be returned fo the current request.
|
|
80
|
+
const result = await this.loadPreAggregationWithKeys();
|
|
81
|
+
const refreshKeyValues = await this.getInvalidationKeyValues();
|
|
82
|
+
return {
|
|
83
|
+
...result,
|
|
84
|
+
refreshKeyValues,
|
|
85
|
+
queryKey: this.isJob
|
|
86
|
+
// We need to return a queryKey value for the jobed build query
|
|
87
|
+
// (initialized by the /cubejs-system/v1/pre-aggregations/jobs
|
|
88
|
+
// endpoint) as a part of the response to make it possible to get a
|
|
89
|
+
// query result from the cache by the other API call.
|
|
90
|
+
? this.preAggregationQueryKey(refreshKeyValues)
|
|
91
|
+
: undefined,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Case 3: pre-agg exists
|
|
96
|
+
const structureVersion = (0, PreAggregations_1.getStructureVersion)(this.preAggregation);
|
|
97
|
+
const getVersionsStarted = new Date();
|
|
98
|
+
const { byStructure } = await this.loadCache.getVersionEntries(this.preAggregation);
|
|
99
|
+
this.logger('Load PreAggregations Tables', {
|
|
100
|
+
preAggregation: this.preAggregation,
|
|
101
|
+
requestId: this.requestId,
|
|
102
|
+
duration: (new Date().getTime() - getVersionsStarted.getTime())
|
|
103
|
+
});
|
|
104
|
+
const versionEntryByStructureVersion = byStructure[`${this.preAggregation.tableName}_${structureVersion}`];
|
|
105
|
+
if (this.externalRefresh) {
|
|
106
|
+
if (!versionEntryByStructureVersion && throwOnMissingPartition) {
|
|
107
|
+
// eslint-disable-next-line no-use-before-define
|
|
108
|
+
throw new Error(PreAggregations_1.PreAggregations.noPreAggregationPartitionsBuiltMessage([this.preAggregation]));
|
|
109
|
+
}
|
|
110
|
+
if (!versionEntryByStructureVersion) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// the rollups are being maintained independently of this instance of cube.js
|
|
115
|
+
// immediately return the latest rollup data that instance already has
|
|
116
|
+
return {
|
|
117
|
+
targetTableName: this.targetTableName(versionEntryByStructureVersion),
|
|
118
|
+
refreshKeyValues: [],
|
|
119
|
+
lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
|
|
120
|
+
buildRangeEnd: versionEntryByStructureVersion.build_range_end,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (versionEntryByStructureVersion) {
|
|
125
|
+
// this triggers an asynchronous/background load of the pre-aggregation but immediately
|
|
126
|
+
// returns the latest data it already has
|
|
127
|
+
this.loadPreAggregationWithKeys().catch(e => {
|
|
128
|
+
if (!(e instanceof ContinueWaitError_1.ContinueWaitError)) {
|
|
129
|
+
this.logger('Error loading pre-aggregation', {
|
|
130
|
+
error: (e.stack || e),
|
|
131
|
+
preAggregation: this.preAggregation,
|
|
132
|
+
requestId: this.requestId
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
return {
|
|
137
|
+
targetTableName: this.targetTableName(versionEntryByStructureVersion),
|
|
138
|
+
refreshKeyValues: [],
|
|
139
|
+
lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
|
|
140
|
+
buildRangeEnd: versionEntryByStructureVersion.build_range_end,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
// no rollup has been built yet - build it synchronously as part of responding to this request
|
|
145
|
+
return this.loadPreAggregationWithKeys();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async loadPreAggregationWithKeys() {
|
|
150
|
+
const invalidationKeys = await this.getPartitionInvalidationKeyValues();
|
|
151
|
+
const contentVersion = this.contentVersion(invalidationKeys);
|
|
152
|
+
const structureVersion = (0, PreAggregations_1.getStructureVersion)(this.preAggregation);
|
|
153
|
+
const versionEntries = await this.loadCache.getVersionEntries(this.preAggregation);
|
|
154
|
+
const getVersionEntryByContentVersion = ({ byContent }) => byContent[`${this.preAggregation.tableName}_${contentVersion}`];
|
|
155
|
+
const versionEntryByContentVersion = getVersionEntryByContentVersion(versionEntries);
|
|
156
|
+
if (versionEntryByContentVersion && !this.forceBuild) {
|
|
157
|
+
const targetTableName = this.targetTableName(versionEntryByContentVersion);
|
|
158
|
+
// No need to block here
|
|
159
|
+
this.updateLastTouch(targetTableName);
|
|
160
|
+
return {
|
|
161
|
+
targetTableName,
|
|
162
|
+
refreshKeyValues: [],
|
|
163
|
+
lastUpdatedAt: versionEntryByContentVersion.last_updated_at,
|
|
164
|
+
buildRangeEnd: versionEntryByContentVersion.build_range_end,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (!this.waitForRenew && !this.forceBuild) {
|
|
168
|
+
const versionEntryByStructureVersion = versionEntries.byStructure[`${this.preAggregation.tableName}_${structureVersion}`];
|
|
169
|
+
if (versionEntryByStructureVersion) {
|
|
170
|
+
const targetTableName = this.targetTableName(versionEntryByStructureVersion);
|
|
171
|
+
// No need to block here
|
|
172
|
+
this.updateLastTouch(targetTableName);
|
|
173
|
+
return {
|
|
174
|
+
targetTableName,
|
|
175
|
+
refreshKeyValues: [],
|
|
176
|
+
lastUpdatedAt: versionEntryByStructureVersion.last_updated_at,
|
|
177
|
+
buildRangeEnd: versionEntryByStructureVersion.build_range_end,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const client = this.preAggregation.external ?
|
|
182
|
+
await this.externalDriverFactory() :
|
|
183
|
+
await this.driverFactory();
|
|
184
|
+
if (!versionEntries.versionEntries.length) {
|
|
185
|
+
await client.createSchemaIfNotExists(this.preAggregation.preAggregationsSchema);
|
|
186
|
+
}
|
|
187
|
+
// ensure we find appropriate structure version before invalidating anything
|
|
188
|
+
const versionEntry = versionEntries.byStructure[`${this.preAggregation.tableName}_${structureVersion}`] ||
|
|
189
|
+
versionEntries.byTableName[this.preAggregation.tableName];
|
|
190
|
+
const newVersionEntry = {
|
|
191
|
+
table_name: this.preAggregation.tableName,
|
|
192
|
+
structure_version: structureVersion,
|
|
193
|
+
content_version: contentVersion,
|
|
194
|
+
last_updated_at: nowTimestamp(client),
|
|
195
|
+
naming_version: 2,
|
|
196
|
+
};
|
|
197
|
+
const mostRecentResult = async () => {
|
|
198
|
+
await this.loadCache.reset(this.preAggregation);
|
|
199
|
+
const lastVersion = getVersionEntryByContentVersion(await this.loadCache.getVersionEntries(this.preAggregation));
|
|
200
|
+
if (!lastVersion) {
|
|
201
|
+
throw new Error(`Pre-aggregation table is not found for ${this.preAggregation.tableName} after it was successfully created`);
|
|
202
|
+
}
|
|
203
|
+
const targetTableName = this.targetTableName(lastVersion);
|
|
204
|
+
this.updateLastTouch(targetTableName);
|
|
205
|
+
return {
|
|
206
|
+
targetTableName,
|
|
207
|
+
refreshKeyValues: [],
|
|
208
|
+
lastUpdatedAt: lastVersion.last_updated_at,
|
|
209
|
+
buildRangeEnd: lastVersion.build_range_end,
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
if (this.forceBuild) {
|
|
213
|
+
this.logger('Force build pre-aggregation', {
|
|
214
|
+
preAggregation: this.preAggregation,
|
|
215
|
+
requestId: this.requestId,
|
|
216
|
+
metadata: this.metadata,
|
|
217
|
+
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
218
|
+
newVersionEntry
|
|
219
|
+
});
|
|
220
|
+
if (this.isJob) {
|
|
221
|
+
// We don't want to wait for the jobed build query result. So we run the
|
|
222
|
+
// executeInQueue method and immediately return the LoadPreAggregationResult object.
|
|
223
|
+
this
|
|
224
|
+
.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry)
|
|
225
|
+
.catch((e) => {
|
|
226
|
+
this.logger('Pre-aggregations build job error', {
|
|
227
|
+
preAggregation: this.preAggregation,
|
|
228
|
+
requestId: this.requestId,
|
|
229
|
+
newVersionEntry,
|
|
230
|
+
error: (e.stack || e),
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
const targetTableName = this.targetTableName(newVersionEntry);
|
|
234
|
+
this.updateLastTouch(targetTableName);
|
|
235
|
+
return {
|
|
236
|
+
targetTableName,
|
|
237
|
+
refreshKeyValues: [],
|
|
238
|
+
lastUpdatedAt: newVersionEntry.last_updated_at,
|
|
239
|
+
buildRangeEnd: this.preAggregation.buildRangeEnd,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
await this.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry);
|
|
244
|
+
return mostRecentResult();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (versionEntry) {
|
|
248
|
+
if (versionEntry.structure_version !== newVersionEntry.structure_version) {
|
|
249
|
+
this.logger('Invalidating pre-aggregation structure', {
|
|
250
|
+
preAggregation: this.preAggregation,
|
|
251
|
+
requestId: this.requestId,
|
|
252
|
+
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
253
|
+
newVersionEntry
|
|
254
|
+
});
|
|
255
|
+
await this.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry);
|
|
256
|
+
return mostRecentResult();
|
|
257
|
+
}
|
|
258
|
+
else if (versionEntry.content_version !== newVersionEntry.content_version) {
|
|
259
|
+
if (this.waitForRenew) {
|
|
260
|
+
this.logger('Waiting for pre-aggregation renew', {
|
|
261
|
+
preAggregation: this.preAggregation,
|
|
262
|
+
requestId: this.requestId,
|
|
263
|
+
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
264
|
+
newVersionEntry
|
|
265
|
+
});
|
|
266
|
+
await this.executeInQueue(invalidationKeys, this.priority(0), newVersionEntry);
|
|
267
|
+
return mostRecentResult();
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
this.scheduleRefresh(invalidationKeys, newVersionEntry);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
this.logger('Creating pre-aggregation from scratch', {
|
|
276
|
+
preAggregation: this.preAggregation,
|
|
277
|
+
requestId: this.requestId,
|
|
278
|
+
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
279
|
+
newVersionEntry
|
|
280
|
+
});
|
|
281
|
+
await this.executeInQueue(invalidationKeys, this.priority(10), newVersionEntry);
|
|
282
|
+
return mostRecentResult();
|
|
283
|
+
}
|
|
284
|
+
const targetTableName = this.targetTableName(versionEntry);
|
|
285
|
+
this.updateLastTouch(targetTableName);
|
|
286
|
+
return {
|
|
287
|
+
targetTableName,
|
|
288
|
+
refreshKeyValues: [],
|
|
289
|
+
lastUpdatedAt: versionEntry.last_updated_at,
|
|
290
|
+
buildRangeEnd: versionEntry.build_range_end,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
updateLastTouch(tableName) {
|
|
294
|
+
this.preAggregations.updateLastTouch(tableName).catch(e => {
|
|
295
|
+
this.logger('Error on pre-aggregation touch', {
|
|
296
|
+
error: (e.stack || e), preAggregation: this.preAggregation, requestId: this.requestId,
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
contentVersion(invalidationKeys) {
|
|
301
|
+
const versionArray = [this.preAggregation.structureVersionLoadSql || this.preAggregation.loadSql];
|
|
302
|
+
if (this.preAggregation.indexesSql && this.preAggregation.indexesSql.length) {
|
|
303
|
+
versionArray.push(this.preAggregation.indexesSql);
|
|
304
|
+
}
|
|
305
|
+
if (this.preAggregation.streamOffset) {
|
|
306
|
+
versionArray.push(this.preAggregation.streamOffset);
|
|
307
|
+
}
|
|
308
|
+
if (this.preAggregation.outputColumnTypes) {
|
|
309
|
+
versionArray.push(this.preAggregation.outputColumnTypes);
|
|
310
|
+
}
|
|
311
|
+
versionArray.push(invalidationKeys);
|
|
312
|
+
return (0, PreAggregations_1.version)(versionArray);
|
|
313
|
+
}
|
|
314
|
+
priority(defaultValue) {
|
|
315
|
+
return this.preAggregation.priority != null ? this.preAggregation.priority : defaultValue;
|
|
316
|
+
}
|
|
317
|
+
getInvalidationKeyValues() {
|
|
318
|
+
return Promise.all((this.preAggregation.invalidateKeyQueries || []).map((sqlQuery) => this.loadCache.keyQueryResult(sqlQuery, this.waitForRenew, this.priority(10))));
|
|
319
|
+
}
|
|
320
|
+
getPartitionInvalidationKeyValues() {
|
|
321
|
+
if (this.preAggregation.partitionInvalidateKeyQueries) {
|
|
322
|
+
return Promise.all((this.preAggregation.partitionInvalidateKeyQueries || []).map((sqlQuery) => this.loadCache.keyQueryResult(sqlQuery, this.waitForRenew, this.priority(10))));
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
return this.getInvalidationKeyValues();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
scheduleRefresh(invalidationKeys, newVersionEntry) {
|
|
329
|
+
this.logger('Refreshing pre-aggregation content', {
|
|
330
|
+
preAggregation: this.preAggregation,
|
|
331
|
+
requestId: this.requestId,
|
|
332
|
+
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
333
|
+
newVersionEntry
|
|
334
|
+
});
|
|
335
|
+
this.executeInQueue(invalidationKeys, this.priority(0), newVersionEntry)
|
|
336
|
+
.catch(e => {
|
|
337
|
+
if (!(e instanceof ContinueWaitError_1.ContinueWaitError)) {
|
|
338
|
+
this.logger('Error refreshing pre-aggregation', {
|
|
339
|
+
error: (e.stack || e), preAggregation: this.preAggregation, requestId: this.requestId
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
async executeInQueue(invalidationKeys, priority, newVersionEntry) {
|
|
345
|
+
const queue = await this.preAggregations.getQueue(this.preAggregation.dataSource);
|
|
346
|
+
return queue.executeInQueue('query', this.preAggregationQueryKey(invalidationKeys), {
|
|
347
|
+
preAggregation: this.preAggregation,
|
|
348
|
+
preAggregationsTablesToTempTables: this.preAggregationsTablesToTempTables,
|
|
349
|
+
newVersionEntry,
|
|
350
|
+
requestId: this.requestId,
|
|
351
|
+
invalidationKeys,
|
|
352
|
+
forceBuild: this.forceBuild,
|
|
353
|
+
isJob: this.isJob,
|
|
354
|
+
metadata: this.metadata,
|
|
355
|
+
orphanedTimeout: this.orphanedTimeout,
|
|
356
|
+
}, priority,
|
|
357
|
+
// eslint-disable-next-line no-use-before-define
|
|
358
|
+
{ stageQueryKey: PreAggregations_1.PreAggregations.preAggregationQueryCacheKey(this.preAggregation), requestId: this.requestId });
|
|
359
|
+
}
|
|
360
|
+
preAggregationQueryKey(invalidationKeys) {
|
|
361
|
+
return this.preAggregation.indexesSql && this.preAggregation.indexesSql.length ?
|
|
362
|
+
[this.preAggregation.loadSql, this.preAggregation.indexesSql, invalidationKeys] :
|
|
363
|
+
[this.preAggregation.loadSql, invalidationKeys];
|
|
364
|
+
}
|
|
365
|
+
targetTableName(versionEntry) {
|
|
366
|
+
// eslint-disable-next-line no-use-before-define
|
|
367
|
+
return PreAggregations_1.PreAggregations.targetTableName(versionEntry);
|
|
368
|
+
}
|
|
369
|
+
refresh(newVersionEntry, invalidationKeys, client) {
|
|
370
|
+
this.updateLastTouch(this.targetTableName(newVersionEntry));
|
|
371
|
+
let refreshStrategy = this.refreshStoreInSourceStrategy;
|
|
372
|
+
if (this.preAggregation.external) {
|
|
373
|
+
const readOnly = this.preAggregation.readOnly ||
|
|
374
|
+
client.config && client.config.readOnly ||
|
|
375
|
+
client.readOnly && (typeof client.readOnly === 'boolean' ? client.readOnly : client.readOnly());
|
|
376
|
+
if (readOnly) {
|
|
377
|
+
refreshStrategy = this.refreshReadOnlyExternalStrategy;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
refreshStrategy = this.refreshWriteStrategy;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return (0, base_driver_1.cancelCombinator)(saveCancelFn => refreshStrategy.bind(this)(client, newVersionEntry, saveCancelFn, invalidationKeys));
|
|
384
|
+
}
|
|
385
|
+
logExecutingSql(payload) {
|
|
386
|
+
this.logger('Executing Load Pre Aggregation SQL', payload);
|
|
387
|
+
}
|
|
388
|
+
queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry) {
|
|
389
|
+
return {
|
|
390
|
+
queryKey: this.preAggregationQueryKey(invalidationKeys),
|
|
391
|
+
query,
|
|
392
|
+
values: params,
|
|
393
|
+
targetTableName,
|
|
394
|
+
requestId: this.requestId,
|
|
395
|
+
newVersionEntry,
|
|
396
|
+
buildRangeEnd: this.preAggregation.buildRangeEnd,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
async refreshStoreInSourceStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
400
|
+
const [loadSql, params] = Array.isArray(this.preAggregation.loadSql) ? this.preAggregation.loadSql : [this.preAggregation.loadSql, []];
|
|
401
|
+
const targetTableName = this.targetTableName(newVersionEntry);
|
|
402
|
+
const query = QueryCache_1.QueryCache.replacePreAggregationTableNames(loadSql, this.preAggregationsTablesToTempTables).replace(this.preAggregation.tableName, targetTableName);
|
|
403
|
+
const queryOptions = this.queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry);
|
|
404
|
+
this.logExecutingSql(queryOptions);
|
|
405
|
+
try {
|
|
406
|
+
// TODO move index creation to the driver
|
|
407
|
+
await saveCancelFn(client.loadPreAggregationIntoTable(targetTableName, query, params, {
|
|
408
|
+
streamOffset: this.preAggregation.streamOffset,
|
|
409
|
+
outputColumnTypes: this.preAggregation.outputColumnTypes,
|
|
410
|
+
...queryOptions
|
|
411
|
+
}));
|
|
412
|
+
await this.createIndexes(client, newVersionEntry, saveCancelFn, queryOptions);
|
|
413
|
+
await this.loadCache.fetchTables(this.preAggregation);
|
|
414
|
+
}
|
|
415
|
+
finally {
|
|
416
|
+
// We must clean orphaned in any cases: success or exception
|
|
417
|
+
await this.dropOrphanedTables(client, targetTableName, saveCancelFn, false, queryOptions);
|
|
418
|
+
await this.loadCache.fetchTables(this.preAggregation);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
async refreshWriteStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
422
|
+
const capabilities = client?.capabilities();
|
|
423
|
+
const withTempTable = !(capabilities?.unloadWithoutTempTable);
|
|
424
|
+
const dropSourceTempTable = !capabilities?.streamingSource;
|
|
425
|
+
return this.runWriteStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys, withTempTable, dropSourceTempTable);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Runs export strategy with write access in data source
|
|
429
|
+
*/
|
|
430
|
+
async runWriteStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys, withTempTable, dropSourceTempTable) {
|
|
431
|
+
if (withTempTable) {
|
|
432
|
+
await client.createSchemaIfNotExists(this.preAggregation.preAggregationsSchema);
|
|
433
|
+
}
|
|
434
|
+
const targetTableName = this.targetTableName(newVersionEntry);
|
|
435
|
+
const queryOptions = await this.prepareWriteStrategy(client, targetTableName, newVersionEntry, saveCancelFn, invalidationKeys, withTempTable);
|
|
436
|
+
try {
|
|
437
|
+
const tableData = await this.downloadExternalPreAggregation(client, newVersionEntry, saveCancelFn, queryOptions, withTempTable);
|
|
438
|
+
try {
|
|
439
|
+
await this.uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn, queryOptions);
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
if (tableData && tableData.release) {
|
|
443
|
+
await tableData.release();
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
finally {
|
|
448
|
+
await this.cleanupWriteStrategy(client, targetTableName, queryOptions, saveCancelFn, withTempTable, dropSourceTempTable);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Cleanup tables after write strategy
|
|
453
|
+
*/
|
|
454
|
+
async cleanupWriteStrategy(client, targetTableName, queryOptions, saveCancelFn, withTempTable, dropSourceTempTable) {
|
|
455
|
+
if (withTempTable && dropSourceTempTable) {
|
|
456
|
+
await this.withDropLock(false, async () => {
|
|
457
|
+
this.logger('Dropping source temp table', queryOptions);
|
|
458
|
+
const actualTables = await client.getTablesQuery(this.preAggregation.preAggregationsSchema);
|
|
459
|
+
const mappedActualTables = actualTables.map(t => `${this.preAggregation.preAggregationsSchema}.${t.table_name || t.TABLE_NAME}`);
|
|
460
|
+
if (mappedActualTables.includes(targetTableName)) {
|
|
461
|
+
await client.dropTable(targetTableName);
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
// We must clean orphaned in any cases: success or exception
|
|
466
|
+
await this.loadCache.fetchTables(this.preAggregation);
|
|
467
|
+
await this.dropOrphanedTables(client, targetTableName, saveCancelFn, false, queryOptions);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Create table (if required) and prepares query options object
|
|
471
|
+
*/
|
|
472
|
+
async prepareWriteStrategy(client, targetTableName, newVersionEntry, saveCancelFn, invalidationKeys, withTempTable) {
|
|
473
|
+
if (withTempTable) {
|
|
474
|
+
const [loadSql, params] = Array.isArray(this.preAggregation.loadSql) ? this.preAggregation.loadSql : [this.preAggregation.loadSql, []];
|
|
475
|
+
const query = QueryCache_1.QueryCache.replacePreAggregationTableNames(loadSql, this.preAggregationsTablesToTempTables).replace(this.preAggregation.tableName, targetTableName);
|
|
476
|
+
const queryOptions = this.queryOptions(invalidationKeys, query, params, targetTableName, newVersionEntry);
|
|
477
|
+
this.logExecutingSql(queryOptions);
|
|
478
|
+
await saveCancelFn(client.loadPreAggregationIntoTable(targetTableName, query, params, {
|
|
479
|
+
streamOffset: this.preAggregation.streamOffset,
|
|
480
|
+
outputColumnTypes: this.preAggregation.outputColumnTypes,
|
|
481
|
+
...queryOptions
|
|
482
|
+
}));
|
|
483
|
+
return queryOptions;
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
const [sql, params] = Array.isArray(this.preAggregation.sql) ? this.preAggregation.sql : [this.preAggregation.sql, []];
|
|
487
|
+
const queryOptions = this.queryOptions(invalidationKeys, sql, params, targetTableName, newVersionEntry);
|
|
488
|
+
this.logExecutingSql(queryOptions);
|
|
489
|
+
return queryOptions;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Strategy to copy pre-aggregation from source db (for read-only permissions) to external data
|
|
494
|
+
*/
|
|
495
|
+
async refreshReadOnlyExternalStrategy(client, newVersionEntry, saveCancelFn, invalidationKeys) {
|
|
496
|
+
const [sql, params] = Array.isArray(this.preAggregation.sql) ? this.preAggregation.sql : [this.preAggregation.sql, []];
|
|
497
|
+
const queryOptions = this.queryOptions(invalidationKeys, sql, params, this.targetTableName(newVersionEntry), newVersionEntry);
|
|
498
|
+
this.logExecutingSql(queryOptions);
|
|
499
|
+
this.logger('Downloading external pre-aggregation via query', queryOptions);
|
|
500
|
+
const externalDriver = await this.externalDriverFactory();
|
|
501
|
+
const capabilities = externalDriver.capabilities && externalDriver.capabilities();
|
|
502
|
+
let tableData;
|
|
503
|
+
if (capabilities.csvImport && client.unloadFromQuery && await client.isUnloadSupported(this.getUnloadOptions())) {
|
|
504
|
+
tableData = await saveCancelFn(client.unloadFromQuery(sql, params, this.getUnloadOptions())).catch((error) => {
|
|
505
|
+
this.logger('Downloading external pre-aggregation via query error', {
|
|
506
|
+
...queryOptions,
|
|
507
|
+
error: error.stack || error.message
|
|
508
|
+
});
|
|
509
|
+
throw error;
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
tableData = await saveCancelFn(client.downloadQueryResults(sql, params, {
|
|
514
|
+
streamOffset: this.preAggregation.streamOffset,
|
|
515
|
+
outputColumnTypes: this.preAggregation.outputColumnTypes,
|
|
516
|
+
...queryOptions,
|
|
517
|
+
...capabilities,
|
|
518
|
+
...this.getStreamingOptions(),
|
|
519
|
+
})).catch((error) => {
|
|
520
|
+
this.logger('Downloading external pre-aggregation via query error', {
|
|
521
|
+
...queryOptions,
|
|
522
|
+
error: error.stack || error.message
|
|
523
|
+
});
|
|
524
|
+
throw error;
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
this.logger('Downloading external pre-aggregation via query completed', {
|
|
528
|
+
...queryOptions,
|
|
529
|
+
isUnloadSupported: (0, base_driver_1.isDownloadTableCSVData)(tableData)
|
|
530
|
+
});
|
|
531
|
+
try {
|
|
532
|
+
await this.uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn, queryOptions);
|
|
533
|
+
}
|
|
534
|
+
finally {
|
|
535
|
+
if (tableData.release) {
|
|
536
|
+
await tableData.release();
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
await this.loadCache.fetchTables(this.preAggregation);
|
|
540
|
+
}
|
|
541
|
+
getUnloadOptions() {
|
|
542
|
+
return {
|
|
543
|
+
// Default: 16mb for Snowflake, Should be specified in MBs, because drivers convert it
|
|
544
|
+
maxFileSize: 64
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
getStreamingOptions() {
|
|
548
|
+
return {
|
|
549
|
+
// Default: 16384 (16KB), or 16 for objectMode streams. PostgreSQL/MySQL use object streams
|
|
550
|
+
highWaterMark: 10000
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* prepares download data for future cube store usage
|
|
555
|
+
*/
|
|
556
|
+
async downloadExternalPreAggregation(client, newVersionEntry, saveCancelFn, queryOptions, withTempTable) {
|
|
557
|
+
const table = this.targetTableName(newVersionEntry);
|
|
558
|
+
this.logger('Downloading external pre-aggregation', queryOptions);
|
|
559
|
+
try {
|
|
560
|
+
const externalDriver = await this.externalDriverFactory();
|
|
561
|
+
const capabilities = externalDriver.capabilities && externalDriver.capabilities();
|
|
562
|
+
let tableData;
|
|
563
|
+
if (withTempTable) {
|
|
564
|
+
tableData = await this.getTableDataWithTempTable(client, table, saveCancelFn, queryOptions, capabilities);
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
tableData = await this.getTableDataWithoutTempTable(client, table, saveCancelFn, queryOptions, capabilities);
|
|
568
|
+
}
|
|
569
|
+
this.logger('Downloading external pre-aggregation completed', {
|
|
570
|
+
...queryOptions,
|
|
571
|
+
isUnloadSupported: (0, base_driver_1.isDownloadTableCSVData)(tableData)
|
|
572
|
+
});
|
|
573
|
+
return tableData;
|
|
574
|
+
}
|
|
575
|
+
catch (error) {
|
|
576
|
+
this.logger('Downloading external pre-aggregation error', {
|
|
577
|
+
...queryOptions,
|
|
578
|
+
error: error?.stack || error?.message
|
|
579
|
+
});
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
/**
|
|
584
|
+
* prepares download data when temp table = true
|
|
585
|
+
*/
|
|
586
|
+
async getTableDataWithTempTable(client, table, saveCancelFn, queryOptions, externalDriverCapabilities) {
|
|
587
|
+
let tableData;
|
|
588
|
+
if (externalDriverCapabilities.csvImport && client.unload && await client.isUnloadSupported(this.getUnloadOptions())) {
|
|
589
|
+
tableData = await saveCancelFn(client.unload(table, this.getUnloadOptions()));
|
|
590
|
+
}
|
|
591
|
+
else if (externalDriverCapabilities.streamImport && client.stream) {
|
|
592
|
+
tableData = await saveCancelFn(client.stream(`SELECT * FROM ${table}`, [], this.getStreamingOptions()));
|
|
593
|
+
if (client.unload) {
|
|
594
|
+
const stream = new StreamObjectsCounter_1.LargeStreamWarning(this.preAggregation.preAggregationId, (msg) => {
|
|
595
|
+
this.logger('Downloading external pre-aggregation warning', {
|
|
596
|
+
...queryOptions,
|
|
597
|
+
error: msg
|
|
598
|
+
});
|
|
599
|
+
});
|
|
600
|
+
tableData.rowStream.pipe(stream);
|
|
601
|
+
tableData.rowStream = stream;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
else {
|
|
605
|
+
tableData = await saveCancelFn(client.downloadTable(table, {
|
|
606
|
+
streamOffset: this.preAggregation.streamOffset,
|
|
607
|
+
outputColumnTypes: this.preAggregation.outputColumnTypes,
|
|
608
|
+
...externalDriverCapabilities
|
|
609
|
+
}));
|
|
610
|
+
}
|
|
611
|
+
if (!tableData.types) {
|
|
612
|
+
tableData.types = await saveCancelFn(client.tableColumnTypes(table));
|
|
613
|
+
}
|
|
614
|
+
return tableData;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* prepares download data when temp table = false
|
|
618
|
+
*/
|
|
619
|
+
async getTableDataWithoutTempTable(client, table, saveCancelFn, queryOptions, externalDriverCapabilities) {
|
|
620
|
+
const [sql, params] = Array.isArray(this.preAggregation.sql) ? this.preAggregation.sql : [this.preAggregation.sql, []];
|
|
621
|
+
let tableData;
|
|
622
|
+
if (externalDriverCapabilities.csvImport && client.unload && await client.isUnloadSupported(this.getUnloadOptions())) {
|
|
623
|
+
return saveCancelFn(client.unload(table, { ...this.getUnloadOptions(), query: { sql, params } }));
|
|
624
|
+
}
|
|
625
|
+
else if (externalDriverCapabilities.streamImport && client.stream) {
|
|
626
|
+
tableData = await saveCancelFn(client.stream(sql, params, this.getStreamingOptions()));
|
|
627
|
+
if (client.unload) {
|
|
628
|
+
const stream = new StreamObjectsCounter_1.LargeStreamWarning(this.preAggregation.preAggregationId, (msg) => {
|
|
629
|
+
this.logger('Downloading external pre-aggregation warning', {
|
|
630
|
+
...queryOptions,
|
|
631
|
+
error: msg
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
tableData.rowStream.pipe(stream);
|
|
635
|
+
tableData.rowStream = stream;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
tableData = { rows: await saveCancelFn(client.query(sql, params)) };
|
|
640
|
+
}
|
|
641
|
+
if (!tableData.types && client.queryColumnTypes) {
|
|
642
|
+
tableData.types = await saveCancelFn(client.queryColumnTypes(sql, params));
|
|
643
|
+
}
|
|
644
|
+
return tableData;
|
|
645
|
+
}
|
|
646
|
+
async uploadExternalPreAggregation(tableData, newVersionEntry, saveCancelFn, queryOptions) {
|
|
647
|
+
const externalDriver = await this.externalDriverFactory();
|
|
648
|
+
const table = this.targetTableName(newVersionEntry);
|
|
649
|
+
this.logger('Uploading external pre-aggregation', queryOptions);
|
|
650
|
+
await saveCancelFn(externalDriver.uploadTableWithIndexes(table, tableData.types, tableData, this.prepareIndexesSql(newVersionEntry, queryOptions), this.preAggregation.uniqueKeyColumns, queryOptions, {
|
|
651
|
+
aggregationsColumns: this.preAggregation.aggregationsColumns,
|
|
652
|
+
createTableIndexes: this.prepareCreateTableIndexes(newVersionEntry),
|
|
653
|
+
sealAt: this.preAggregation.sealAt
|
|
654
|
+
})).catch((error) => {
|
|
655
|
+
this.logger('Uploading external pre-aggregation error', {
|
|
656
|
+
...queryOptions,
|
|
657
|
+
error: error?.stack || error?.message
|
|
658
|
+
});
|
|
659
|
+
throw error;
|
|
660
|
+
});
|
|
661
|
+
this.logger('Uploading external pre-aggregation completed', queryOptions);
|
|
662
|
+
await this.loadCache.fetchTables(this.preAggregation);
|
|
663
|
+
await this.dropOrphanedTables(externalDriver, table, saveCancelFn, true, queryOptions);
|
|
664
|
+
}
|
|
665
|
+
async createIndexes(driver, newVersionEntry, saveCancelFn, queryOptions) {
|
|
666
|
+
const indexesSql = this.prepareIndexesSql(newVersionEntry, queryOptions);
|
|
667
|
+
for (let i = 0; i < indexesSql.length; i++) {
|
|
668
|
+
const [query, params] = indexesSql[i].sql;
|
|
669
|
+
await saveCancelFn(driver.query(query, params));
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
prepareIndexesSql(newVersionEntry, queryOptions) {
|
|
673
|
+
if (!this.preAggregation.indexesSql || !this.preAggregation.indexesSql.length) {
|
|
674
|
+
return [];
|
|
675
|
+
}
|
|
676
|
+
return this.preAggregation.indexesSql.map(({ sql, indexName }) => {
|
|
677
|
+
const [query, params] = sql;
|
|
678
|
+
const indexVersionEntry = {
|
|
679
|
+
...newVersionEntry,
|
|
680
|
+
table_name: indexName
|
|
681
|
+
};
|
|
682
|
+
this.logger('Creating pre-aggregation index', queryOptions);
|
|
683
|
+
const resultingSql = QueryCache_1.QueryCache.replacePreAggregationTableNames(query, this.preAggregationsTablesToTempTables.concat([
|
|
684
|
+
[this.preAggregation.tableName, { targetTableName: this.targetTableName(newVersionEntry) }],
|
|
685
|
+
[indexName, { targetTableName: this.targetTableName(indexVersionEntry) }]
|
|
686
|
+
]));
|
|
687
|
+
return { sql: [resultingSql, params] };
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
prepareCreateTableIndexes(newVersionEntry) {
|
|
691
|
+
if (!this.preAggregation.createTableIndexes || !this.preAggregation.createTableIndexes.length) {
|
|
692
|
+
return [];
|
|
693
|
+
}
|
|
694
|
+
return this.preAggregation.createTableIndexes.map(({ indexName, type, columns }) => {
|
|
695
|
+
const indexVersionEntry = {
|
|
696
|
+
...newVersionEntry,
|
|
697
|
+
table_name: indexName
|
|
698
|
+
};
|
|
699
|
+
return { indexName: this.targetTableName(indexVersionEntry), type, columns };
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
async withDropLock(external, lockFn) {
|
|
703
|
+
const lockKey = this.dropLockKey(external);
|
|
704
|
+
return this.queryCache.withLock(lockKey, 60 * 5, lockFn);
|
|
705
|
+
}
|
|
706
|
+
async dropOrphanedTables(client, justCreatedTable, saveCancelFn, external, queryOptions) {
|
|
707
|
+
await this.preAggregations.addTableUsed(justCreatedTable);
|
|
708
|
+
return this.withDropLock(external, async () => {
|
|
709
|
+
this.logger('Dropping orphaned tables', { ...queryOptions, external });
|
|
710
|
+
const actualTables = await client.getTablesQuery(this.preAggregation.preAggregationsSchema);
|
|
711
|
+
const versionEntries = (0, PreAggregations_1.tablesToVersionEntries)(this.preAggregation.preAggregationsSchema, actualTables);
|
|
712
|
+
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);
|
|
713
|
+
const structureVersionsToSave = ramda_1.default.pipe(ramda_1.default.filter((v) => (new Date().getTime() - v.last_updated_at <
|
|
714
|
+
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);
|
|
715
|
+
const refreshEndReached = await this.preAggregations.getRefreshEndReached();
|
|
716
|
+
const toSave = this.preAggregations.dropPreAggregationsWithoutTouch && refreshEndReached
|
|
717
|
+
? (await this.preAggregations.tablesUsed())
|
|
718
|
+
.concat(await this.preAggregations.tablesTouched())
|
|
719
|
+
.concat([justCreatedTable])
|
|
720
|
+
: (await this.preAggregations.tablesUsed())
|
|
721
|
+
.concat(structureVersionsToSave.map(v => this.targetTableName(v)))
|
|
722
|
+
.concat(versionEntriesToSave.map(v => this.targetTableName(v)))
|
|
723
|
+
.concat([justCreatedTable]);
|
|
724
|
+
const toDrop = actualTables
|
|
725
|
+
.map(t => `${this.preAggregation.preAggregationsSchema}.${t.table_name || t.TABLE_NAME}`)
|
|
726
|
+
.filter(t => toSave.indexOf(t) === -1);
|
|
727
|
+
await Promise.all(toDrop.map(table => saveCancelFn(client.dropTable(table))));
|
|
728
|
+
this.logger('Dropping orphaned tables completed', {
|
|
729
|
+
...queryOptions,
|
|
730
|
+
external,
|
|
731
|
+
tablesToDrop: JSON.stringify(toDrop),
|
|
732
|
+
});
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
dropLockKey(external) {
|
|
736
|
+
return external
|
|
737
|
+
? 'drop-orphaned-tables-external'
|
|
738
|
+
: `drop-orphaned-tables:${this.preAggregation.dataSource}`;
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
exports.PreAggregationLoader = PreAggregationLoader;
|
|
742
|
+
//# sourceMappingURL=PreAggregationLoader.js.map
|