006_timescale.down.sql 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. -- 006_timescale.down.sql
  2. -- Reverse M7. Removes the retention policy, then converts
  3. -- the hypertable back to a plain table. The data is
  4. -- preserved; only the chunk metadata is dropped.
  5. --
  6. -- NOTE: Timescale's `detach_database` or `hypertable_to_table`
  7. -- is a no-op in modern Timescale — once a table is a
  8. -- hypertable, you can't truly "downgrade" it without a
  9. -- table swap. We use the documented pattern of creating a
  10. -- plain shadow table, copying data over, and renaming.
  11. -- This is destructive on the timeline dimension but
  12. -- preserves all rows.
  13. -- 1. Remove the retention policy. After this, Timescale
  14. -- will no longer auto-drop chunks.
  15. SELECT remove_retention_policy('deliveries', if_exists => true);
  16. -- 2. Timescale has no clean "downgrade a hypertable"
  17. -- primitive. The recommended approach for a rollback is:
  18. -- a) create a plain shadow table with the same schema
  19. -- b) INSERT ... SELECT all rows
  20. -- c) drop the hypertable, rename the shadow
  21. -- We do that here. Note this is non-atomic and can take
  22. -- a while on large tables.
  23. CREATE TABLE IF NOT EXISTS deliveries_plain (
  24. id BIGSERIAL PRIMARY KEY,
  25. alert_id TEXT NOT NULL,
  26. company_id TEXT NOT NULL,
  27. individual_id TEXT NOT NULL,
  28. channel TEXT NOT NULL,
  29. target TEXT NOT NULL,
  30. status TEXT NOT NULL DEFAULT 'pending',
  31. attempts INT NOT NULL DEFAULT 0,
  32. last_error TEXT,
  33. payload JSONB,
  34. created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  35. sent_at TIMESTAMPTZ,
  36. next_attempt_at TIMESTAMPTZ
  37. );
  38. -- The hypertable has the same columns, so a plain
  39. -- INSERT ... SELECT is enough. We add the original
  40. -- indexes back too.
  41. CREATE INDEX IF NOT EXISTS idx_deliveries_plain_company_alert
  42. ON deliveries_plain(company_id, alert_id);
  43. CREATE INDEX IF NOT EXISTS idx_deliveries_plain_status
  44. ON deliveries_plain(status) WHERE status IN ('pending','failed');
  45. -- Drop the hypertable and rename. This breaks the FK
  46. -- references and recreates the original table layout.
  47. DROP TABLE IF EXISTS deliveries CASCADE;
  48. ALTER TABLE deliveries_plain RENAME TO deliveries;
  49. -- The original 002_deliveries.up.sql had these indexes
  50. -- too; recreate them.
  51. CREATE INDEX IF NOT EXISTS idx_deliveries_company_alert
  52. ON deliveries(company_id, alert_id);
  53. CREATE INDEX IF NOT EXISTS idx_deliveries_status
  54. ON deliveries(status) WHERE status IN ('pending','failed');