For the coverage-aware holiday-calendar API in TSAPI core (db_base
holiday_calendar__get / __set_coverage / __set_metadata / __upsert).
- meta.holiday_calendars (name, description, covered_from, covered_to,
source, updated_at): a calendar exists when it has a row here, not
when it has holidays (retires the 9999-12-31 sentinel row).
covered_from/to: the range over which the closure list is complete;
both set or both NULL, from <= to (holiday_calendars_coverage_check).
- Calendar names are citext in every table (registry, holidays.calendar_name,
exchanges.default_holiday_calendar, instruments.holiday_calendar):
stored as given, unique and matched case-insensitively -- also in the
foreign keys -- as the native TSAPI backend does with COLLATE NOCASE.
New extension citext (00_extensions.sql). Name check: non-empty,
trimmed, <= 50 characters.
- FKs: holidays -> registry ON DELETE CASCADE; exchanges/instruments ->
registry ON DELETE RESTRICT (a calendar in use cannot be dropped);
ON UPDATE CASCADE everywhere.
- meta.series.num_records dropped. Only some write paths maintained it
(never C++), it sometimes held an estimate, and it was NULL for a series
never written to. Clients ask the table: count(*), or
SELECT EXISTS (SELECT 1 FROM <table>) for "is it empty?".
- find_schema_problems() covers the new table, columns, constraints and
extension, and runs with search_path = pg_catalog so format_type()
reports 'public.citext' whatever the caller's search_path.
Verified on a fresh database (PG 17): run_setup.py installs it and
find_schema_problems() returns zero rows, also for a caller without
public on the search_path; constraint behaviour checked by hand
(case-insensitive duplicate refused, FK matches any spelling, RESTRICT
and CASCADE, coverage and name checks).
Re-provision databases (no migration).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- meta.series_schemas (name, description, created_at, created_by), seeded
with 'series'. FK series_db_schema_fkey from meta.series.db_schema: a
series may only live in a registered schema, for every client.
Unregistered schemas belong to the user and are never touched.
- CHECK series_schemas_name_check and series_table_name_check enforce the
shared lower-case identifier rule in the database.
- meta.find_schema_problems() covers the registry and reports a registered
schema that no longer exists; user schemas are not examined.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Single source of truth for the timeseries PostgreSQL schema shared by the
Python (TSAPI_SERIESDB_PG_PY) and C++ (TSAPI_POSTGRES_CPP) libraries. SQL
seeded byte-for-byte from TSAPI_SERIESDB_PG_PY/tsapi_pgdb/sql on 2026-09-02.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>