@timescaledb/core
Version:
The `@timescaledb/core` package provides fundamental building blocks for working with TimescaleDB in TypeScript/JavaScript applications. It includes SQL query builders and utilities for managing hypertables, continuous aggregates, compression, and other T
143 lines • 6.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RollupBuilder = void 0;
const utils_1 = require("@timescaledb/utils");
const candlestick_1 = require("./candlestick");
const debug_1 = require("./debug");
const debug = (0, debug_1.debugCore)('RollupBuilder');
class RollupInspectBuilder {
constructor(config) {
this.config = config;
}
build() {
debug(`Building inspect query for rollup '${this.config.rollupOptions.name}'`);
if (!this.config || !this.config.rollupOptions) {
throw new Error('Invalid rollup configuration 1');
}
const sourceView = (0, utils_1.escapeLiteral)(this.config.rollupOptions.sourceView);
const rollupView = (0, utils_1.escapeLiteral)(this.config.rollupOptions.name);
const result = `
SELECT
EXISTS (
SELECT FROM information_schema.views
WHERE table_schema = 'public'
AND table_name = ${sourceView}
) as source_view_exists,
EXISTS (
SELECT FROM information_schema.views
WHERE table_schema = 'public'
AND table_name = ${rollupView}
) as rollup_view_exists;
`;
debug(`Inspect query '${this.config.rollupOptions.name}' built:\n${result}`);
return result;
}
}
class RollupUpBuilder {
constructor(config) {
this.config = config;
this.statements = [];
}
buildRollupSelect(metadata) {
const selectStatements = [];
const bucketInterval = (0, utils_1.escapeLiteral)(this.config.rollupOptions.bucketInterval);
const bucketColumnSource = (0, utils_1.escapeIdentifier)(this.config.rollupOptions.bucketColumn.source || 'bucket');
const bucketColumnTarget = (0, utils_1.escapeIdentifier)(this.config.rollupOptions.bucketColumn.target || 'bucket');
selectStatements.push(`time_bucket(${bucketInterval}::interval, ${bucketColumnSource}) AS ${bucketColumnTarget}`);
const groupColumns = this.config.continuousAggregateOptions.group_columns || [];
for (const column of groupColumns) {
const escapedColumn = (0, utils_1.escapeIdentifier)(column);
selectStatements.push(`${escapedColumn} as ${escapedColumn}`);
}
if (metadata.candlestick) {
const rollupSql = candlestick_1.CandlestickBuilder.generateSQL(metadata.candlestick, true);
if (rollupSql) {
selectStatements.push(rollupSql);
}
}
const rollupSelects = metadata.rollupRules.map((rule) => {
const sourceColumn = (0, utils_1.escapeIdentifier)(rule.sourceColumn);
const targetColumn = (0, utils_1.escapeIdentifier)(rule.targetColumn || 'bucket');
if (rule.aggregateType) {
switch (rule.aggregateType) {
case 'sum':
return `sum(${sourceColumn}) as ${targetColumn}`;
case 'avg':
return `avg(${sourceColumn}) as ${targetColumn}`;
default:
return `rollup(${sourceColumn}) as ${targetColumn}`;
}
}
return `${rule.rollupFn || 'rollup'}(${sourceColumn}) as ${targetColumn}`;
});
selectStatements.push(...rollupSelects);
const sourceView = (0, utils_1.escapeIdentifier)(this.config.rollupOptions.sourceView);
const groupByCols = ['1', ...groupColumns.map((c) => (0, utils_1.escapeIdentifier)(c))];
const groupByClause = groupByCols.join(', ');
const result = `
SELECT
${selectStatements.join(',\n ')}
FROM ${sourceView}
GROUP BY ${groupByClause}${this.config.rollupOptions.materializedOnly ? ' WITH ' : ' WITH NO '}DATA;
`;
return result;
}
build(metadata) {
debug('Building rollup query');
const _metadata = metadata || { rollupRules: this.config.rollupOptions.rollupRules || [] };
const viewName = (0, utils_1.escapeIdentifier)(this.config.rollupOptions.name);
this.statements.push(`CREATE MATERIALIZED VIEW ${viewName}
WITH (timescaledb.continuous) AS ${this.buildRollupSelect(_metadata)}`);
debug(`Rollup query built:\n${this.statements.join('\n')}`);
return this.statements.join('\n');
}
getRefreshPolicy() {
if (!this.config.rollupOptions.refresh_policy)
return null;
debug('Building refresh policy query');
const policy = this.config.rollupOptions.refresh_policy;
const viewName = (0, utils_1.escapeLiteral)(this.config.rollupOptions.name);
const result = `SELECT add_continuous_aggregate_policy(${viewName},
start_offset => INTERVAL ${(0, utils_1.escapeLiteral)(policy.start_offset)},
end_offset => INTERVAL ${(0, utils_1.escapeLiteral)(policy.end_offset)},
schedule_interval => INTERVAL ${(0, utils_1.escapeLiteral)(policy.schedule_interval)}
);`;
debug(`Refresh policy query built:\n${result}`);
return result;
}
}
class RollupDownBuilder {
constructor(config) {
this.config = config;
}
build() {
debug('Building down query');
const statements = [];
const viewName = this.config.rollupOptions.name;
if (this.config.continuousAggregateOptions.refresh_policy) {
statements.push(`SELECT remove_continuous_aggregate_policy(${(0, utils_1.escapeLiteral)(viewName)}, if_exists => true);`);
}
statements.push(`DROP MATERIALIZED VIEW IF EXISTS ${(0, utils_1.escapeIdentifier)(viewName)};`);
debug(`Down query built:\n${statements.join('\n')}`);
return statements;
}
}
class RollupBuilder {
constructor(config) {
this.config = config;
if (!config || !config.rollupOptions) {
throw new Error('Invalid rollup configuration 2');
}
}
up() {
return new RollupUpBuilder(this.config);
}
down() {
return new RollupDownBuilder(this.config);
}
inspect() {
return new RollupInspectBuilder(this.config);
}
}
exports.RollupBuilder = RollupBuilder;
//# sourceMappingURL=rollup.js.map