119 lines
4.7 KiB
JavaScript
119 lines
4.7 KiB
JavaScript
/** @type {import('node-pg-migrate').MigrationBuilder} */
|
|
exports.up = (pgm) => {
|
|
pgm.sql(`CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE`);
|
|
|
|
pgm.createTable(
|
|
'signals',
|
|
{
|
|
real_time: { type: 'timestamptz', notNull: true },
|
|
game_tick: { type: 'bigint', notNull: true },
|
|
combinator: { type: 'text', notNull: true },
|
|
item_key: { type: 'text', notNull: true },
|
|
green: { type: 'integer', notNull: true, default: 0 },
|
|
red: { type: 'integer', notNull: true, default: 0 },
|
|
logistic: { type: 'integer' },
|
|
},
|
|
{ ifNotExists: true },
|
|
);
|
|
|
|
pgm.sql(`SELECT create_hypertable('signals', 'real_time', if_not_exists => true)`);
|
|
pgm.sql(
|
|
`CREATE INDEX IF NOT EXISTS signals_combinator_item_key_real_time_idx ON signals (combinator, item_key, real_time DESC)`,
|
|
);
|
|
pgm.sql(`CREATE INDEX IF NOT EXISTS signals_game_tick_idx ON signals (game_tick DESC)`);
|
|
pgm.sql(`SELECT add_retention_policy('signals', INTERVAL '30 days', if_not_exists => true)`);
|
|
|
|
pgm.createTable(
|
|
'tick_timing',
|
|
{
|
|
real_time: { type: 'timestamptz', notNull: true },
|
|
game_tick: { type: 'bigint', notNull: true },
|
|
combinator: { type: 'text', notNull: true },
|
|
},
|
|
{ ifNotExists: true },
|
|
);
|
|
|
|
pgm.sql(`SELECT create_hypertable('tick_timing', 'real_time', if_not_exists => true)`);
|
|
pgm.sql(
|
|
`CREATE INDEX IF NOT EXISTS tick_timing_combinator_real_time_idx ON tick_timing (combinator, real_time DESC)`,
|
|
);
|
|
pgm.sql(`SELECT add_retention_policy('tick_timing', INTERVAL '30 days', if_not_exists => true)`);
|
|
|
|
pgm.createTable(
|
|
'charts',
|
|
{
|
|
id: { type: 'uuid', primaryKey: true, default: pgm.func('gen_random_uuid()') },
|
|
title: { type: 'text', notNull: true },
|
|
pos_x: { type: 'integer', notNull: true, default: 0 },
|
|
pos_y: { type: 'integer', notNull: true, default: 0 },
|
|
width: { type: 'integer', notNull: true, default: 2 },
|
|
height: { type: 'integer', notNull: true, default: 4 },
|
|
signal_type: { type: 'text', notNull: true, default: 'both' },
|
|
chart_type: { type: 'text', notNull: true, default: 'signals' },
|
|
viz_type: { type: 'text', notNull: true, default: 'line' },
|
|
filter_combinators: { type: 'text[]' },
|
|
filter_items: { type: 'text[]' },
|
|
filter_items_exclude: { type: 'text[]' },
|
|
filter_items_regex: { type: 'boolean', notNull: true, default: false },
|
|
y_min: { type: 'real' },
|
|
y_max: { type: 'real' },
|
|
series_limit: { type: 'integer', notNull: true, default: 20 },
|
|
order_by: { type: 'text', notNull: true, default: 'time' },
|
|
created_at: { type: 'timestamptz', notNull: true, default: pgm.func('now()') },
|
|
},
|
|
{ ifNotExists: true },
|
|
);
|
|
|
|
// Use DO blocks so constraints are idempotent on existing DBs
|
|
pgm.sql(`DO $$ BEGIN
|
|
ALTER TABLE charts ADD CONSTRAINT charts_signal_type_check CHECK (signal_type IN ('green','red','both'));
|
|
EXCEPTION WHEN duplicate_object THEN NULL; END $$`);
|
|
|
|
pgm.sql(`DO $$ BEGIN
|
|
ALTER TABLE charts ADD CONSTRAINT charts_chart_type_check CHECK (chart_type IN ('signals','ups'));
|
|
EXCEPTION WHEN duplicate_object THEN NULL; END $$`);
|
|
|
|
pgm.sql(`DO $$ BEGIN
|
|
ALTER TABLE charts ADD CONSTRAINT charts_viz_type_check CHECK (viz_type IN ('line','table'));
|
|
EXCEPTION WHEN duplicate_object THEN NULL; END $$`);
|
|
|
|
pgm.sql(`DO $$ BEGIN
|
|
ALTER TABLE charts ADD CONSTRAINT charts_order_by_check CHECK (order_by IN ('time','value_asc','value_desc','abs_desc','delta_asc','delta_desc'));
|
|
EXCEPTION WHEN duplicate_object THEN NULL; END $$`);
|
|
|
|
pgm.createTable(
|
|
'alerts',
|
|
{
|
|
id: { type: 'uuid', primaryKey: true, default: pgm.func('gen_random_uuid()') },
|
|
item_key: { type: 'text', notNull: true },
|
|
item_key_is_regex: { type: 'boolean', notNull: true, default: false },
|
|
combinator: { type: 'text' },
|
|
signal_type: { type: 'text', notNull: true, default: 'green' },
|
|
condition: { type: 'text', notNull: true },
|
|
threshold: { type: 'integer', notNull: true },
|
|
active: { type: 'boolean', notNull: true, default: true },
|
|
created_at: { type: 'timestamptz', notNull: true, default: pgm.func('now()') },
|
|
},
|
|
{ ifNotExists: true },
|
|
);
|
|
|
|
pgm.sql(`DO $$ BEGIN
|
|
ALTER TABLE alerts ADD CONSTRAINT alerts_signal_type_check CHECK (signal_type IN ('green','red'));
|
|
EXCEPTION WHEN duplicate_object THEN NULL; END $$`);
|
|
|
|
pgm.sql(`DO $$ BEGIN
|
|
ALTER TABLE alerts ADD CONSTRAINT alerts_condition_check CHECK (condition IN ('above','below'));
|
|
EXCEPTION WHEN duplicate_object THEN NULL; END $$`);
|
|
|
|
pgm.createTable(
|
|
'settings',
|
|
{
|
|
key: { type: 'text', primaryKey: true },
|
|
value: { type: 'text', notNull: true },
|
|
},
|
|
{ ifNotExists: true },
|
|
);
|
|
};
|
|
|
|
exports.down = () => Promise.resolve();
|