Merged in feature/restore-migrations-v2 (pull request #205)

Restore original migrations (001-120) to fix schema_migrations version mismatch

* Restore original migrations (001-120) to fix schema_migrations version mismatch

The previous migration collapse broke deployed databases because:
- Dev database was at version 120 (the real remove_text_extraction migration)
- Main had collapsed migrations (001-012) + stub files (119_stub, 120_stub)
- The migrate tool couldn't find version 119/120 with matching content

This commit restores the original 27 migrations (versions 001-120) from
before the collapse, ensuring backward compatibility with existing databases.
This commit is contained in:
Jay Brown
2026-01-15 23:18:53 +00:00
parent 3639af8b84
commit c10fa98d0a
69 changed files with 1271 additions and 506 deletions
@@ -1,7 +1 @@
-- Migration 001: Extensions and Core Functions (DOWN)
-- Drops in reverse order of creation
DROP DOMAIN IF EXISTS unsignedsmallint;
DROP FUNCTION IF EXISTS isInVersion;
DROP FUNCTION IF EXISTS uuid_generate_v7;
DROP EXTENSION IF EXISTS "pgcrypto";
DROP EXTENSION "pgcrypto";
@@ -1,13 +1,9 @@
-- Migration 001: Extensions and Core Functions
-- Creates PostgreSQL extensions and utility functions used throughout the schema
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
-- UUID v7 generator function (time-ordered UUIDs)
CREATE OR REPLACE FUNCTION uuid_generate_v7()
RETURNS uuid
AS $$
SELECT encode(
create or replace function uuid_generate_v7()
returns uuid
as $$
select encode(
set_bit(
set_bit(
overlay(uuid_send(gen_random_uuid())
@@ -20,24 +16,22 @@ SELECT encode(
),
'hex')::uuid;
$$
LANGUAGE SQL
VOLATILE;
language SQL
volatile;
-- Version checking function for temporal data patterns
CREATE FUNCTION isInVersion(
_version int,
_addedVersion int,
_removedVersion int
)
RETURNS boolean AS $$
RETURNS boolean as $$
BEGIN
RETURN _version IS NULL OR (
RETURN _version is null OR (
_version >= _addedVersion AND
(_removedVersion IS NULL OR _version < _removedVersion)
(_removedVersion is null OR _version < _removedVersion)
);
END;
$$ LANGUAGE plpgsql;
-- Domain for unsigned small integers
CREATE DOMAIN unsignedsmallint AS SMALLINT
CHECK (VALUE >= 0);
@@ -1,4 +0,0 @@
-- Migration 002: Clients (DOWN)
DROP TABLE IF EXISTS clientCanSync;
DROP TABLE IF EXISTS clients;
@@ -1,15 +0,0 @@
-- Migration 002: Clients
-- Core client tables for customer configuration
CREATE TABLE clients (
clientId varchar(255) PRIMARY KEY,
name TEXT NOT NULL,
UNIQUE (name)
);
CREATE TABLE clientCanSync (
syncId uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
clientId varchar(255) NOT NULL,
canSync boolean NOT NULL,
FOREIGN KEY (clientId) REFERENCES clients(clientId)
);
@@ -0,0 +1,7 @@
DROP TABLE queries;
DROP TYPE queryType;
DROP TABLE requiredQueries;
DROP TABLE queryConfigs;
@@ -0,0 +1,79 @@
CREATE TYPE queryType AS ENUM ('context_full', 'json_extractor');
CREATE TABLE queries (
queryId uuid primary key DEFAULT uuid_generate_v7(),
queryType queryType not null
);
CREATE TABLE queryVersions (
queryId uuid not null,
versionId int not null,
addedAt timestamp not null default current_timestamp,
primary key (versionId, queryId),
foreign key (queryId) references queries(queryId)
);
CREATE OR REPLACE FUNCTION setQueryVersionNumber()
RETURNS TRIGGER AS $$
BEGIN
SELECT COALESCE(MAX(versionId), 0) + 1
INTO NEW.versionId
FROM queryVersions
WHERE queryId = NEW.queryId;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER setQueryVersionNumberTrigger
BEFORE INSERT ON queryVersions
FOR EACH ROW
EXECUTE FUNCTION setQueryVersionNumber();
CREATE TABLE queryActiveVersions (
activeVersionEntryId uuid primary key DEFAULT uuid_generate_v7(),
queryId uuid not null,
versionId int not null,
foreign key (queryId, versionId) references queryVersions(queryId, versionId)
);
CREATE TABLE requiredQueries (
requiredQueryEntryId uuid primary key DEFAULT uuid_generate_v7(),
queryId uuid not null,
requiredQueryId uuid not null,
addedVersion int not null,
removedVersion int,
foreign key (queryId) references queries(queryId),
foreign key (requiredQueryId) references queries(queryId),
foreign key (queryId, addedVersion) references queryVersions(queryId, versionId),
foreign key (queryId, removedVersion) references queryVersions(queryId, versionId),
unique (queryId, requiredQueryId, removedVersion)
);
CREATE TABLE queryConfigs (
configId uuid primary key DEFAULT uuid_generate_v7(),
queryId uuid not null,
config jsonb not null,
addedVersion int not null,
removedVersion int,
foreign key (queryId) references queries(queryId),
foreign key (queryId, addedVersion) references queryVersions(queryId, versionId),
foreign key (queryId, removedVersion) references queryVersions(queryId, versionId),
unique (queryId, removedVersion)
);
CREATE OR REPLACE FUNCTION removeQueryConfig()
RETURNS TRIGGER AS $$
BEGIN
UPDATE queryConfigs
SET removedVersion = NEW.addedVersion
WHERE queryId = NEW.queryId and removedVersion is null;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER removeQueryConfigTrigger
BEFORE INSERT ON queryConfigs
FOR EACH ROW
EXECUTE FUNCTION removeQueryConfig();
@@ -0,0 +1 @@
DROP TABLE clients;
@@ -0,0 +1,12 @@
CREATE TABLE clients (
clientId varchar(255) primary key,
name TEXT not null,
UNIQUE (name)
);
CREATE TABLE clientCanSync (
syncId uuid primary key DEFAULT uuid_generate_v7(),
clientId varchar(255) not null,
canSync boolean not null,
foreign key (clientId) references clients(clientId)
);
@@ -1,9 +0,0 @@
-- Migration 003: Collectors (DOWN)
DROP TRIGGER IF EXISTS removeMinCleanVersionTrigger ON collectorMinCleanVersions;
DROP FUNCTION IF EXISTS removeMinCleanVersion;
DROP TABLE IF EXISTS collectorMinCleanVersions;
DROP TABLE IF EXISTS collectorActiveVersions;
DROP TRIGGER IF EXISTS setCollectorVersionNumberTrigger ON collectorVersions;
DROP FUNCTION IF EXISTS setCollectorVersionNumber;
DROP TABLE IF EXISTS collectorVersions;
@@ -1,62 +0,0 @@
-- Migration 003: Collectors (Simplified)
-- Collector versioning and configuration
-- NOTE: collectorMinTextVersions and collectorQueries removed (no longer used)
CREATE TABLE collectorVersions (
clientId varchar(255) NOT NULL,
id int NOT NULL,
addedAt timestamp NOT NULL DEFAULT current_timestamp,
FOREIGN KEY (clientId) REFERENCES clients(clientId),
PRIMARY KEY (id, clientId)
);
CREATE OR REPLACE FUNCTION setCollectorVersionNumber()
RETURNS TRIGGER AS $$
BEGIN
SELECT COALESCE(MAX(id), 0) + 1
INTO NEW.id
FROM collectorVersions
WHERE clientId = NEW.clientId;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER setCollectorVersionNumberTrigger
BEFORE INSERT ON collectorVersions
FOR EACH ROW
EXECUTE FUNCTION setCollectorVersionNumber();
CREATE TABLE collectorActiveVersions (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
clientId varchar(255) NOT NULL,
versionId int NOT NULL,
FOREIGN KEY (clientId, versionId) REFERENCES collectorVersions(clientId, id)
);
CREATE TABLE collectorMinCleanVersions (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
clientId varchar(255) NOT NULL,
versionId bigint NOT NULL,
addedVersion int NOT NULL,
removedVersion int,
FOREIGN KEY (clientId, addedVersion) REFERENCES collectorVersions(clientId, id),
FOREIGN KEY (clientId, removedVersion) REFERENCES collectorVersions(clientId, id),
FOREIGN KEY (clientId) REFERENCES clients(clientId)
);
CREATE OR REPLACE FUNCTION removeMinCleanVersion()
RETURNS TRIGGER AS $$
BEGIN
UPDATE collectorMinCleanVersions
SET removedVersion = NEW.addedVersion
WHERE clientId = NEW.clientId AND removedVersion IS NULL;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER removeMinCleanVersionTrigger
BEFORE INSERT ON collectorMinCleanVersions
FOR EACH ROW
EXECUTE FUNCTION removeMinCleanVersion();
@@ -1,6 +0,0 @@
-- Migration 004: Batch Uploads (DOWN)
DROP INDEX IF EXISTS idx_batch_uploads_status;
DROP INDEX IF EXISTS idx_batch_uploads_client_id;
DROP TABLE IF EXISTS batch_uploads;
DROP TYPE IF EXISTS batch_status;
@@ -0,0 +1,3 @@
DROP TABLE collectorQueries;
DROP TABLE collectors;
@@ -0,0 +1,99 @@
CREATE TABLE collectorVersions (
clientId varchar(255) not null,
id int not null,
addedAt timestamp not null default current_timestamp,
foreign key (clientId) references clients(clientId),
primary key (id, clientId)
);
CREATE OR REPLACE FUNCTION setCollectorVersionNumber()
RETURNS TRIGGER AS $$
BEGIN
SELECT COALESCE(MAX(id), 0) + 1
INTO NEW.id
FROM collectorVersions
WHERE clientId = NEW.clientId;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER setCollectorVersionNumberTrigger
BEFORE INSERT ON collectorVersions
FOR EACH ROW
EXECUTE FUNCTION setCollectorVersionNumber();
CREATE TABLE collectorActiveVersions (
id uuid primary key DEFAULT uuid_generate_v7(),
clientId varchar(255) not null,
versionId int not null,
foreign key (clientId, versionId) references collectorVersions(clientId, id)
);
CREATE TABLE collectorMinCleanVersions (
id uuid primary key DEFAULT uuid_generate_v7(),
clientId varchar(255) not null,
versionId bigint not null,
addedVersion int not null,
removedVersion int,
foreign key (clientId, addedVersion) references collectorVersions(clientId, id),
foreign key (clientId, removedVersion) references collectorVersions(clientId, id),
foreign key (clientId) references clients(clientId)
);
CREATE OR REPLACE FUNCTION removeMinCleanVersion()
RETURNS TRIGGER AS $$
BEGIN
UPDATE collectorMinCleanVersions
SET removedVersion = NEW.addedVersion
WHERE clientId = NEW.clientId and removedVersion is null;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER removeMinCleanVersionTrigger
BEFORE INSERT ON collectorMinCleanVersions
FOR EACH ROW
EXECUTE FUNCTION removeMinCleanVersion();
CREATE TABLE collectorMinTextVersions (
id uuid primary key DEFAULT uuid_generate_v7(),
clientId varchar(255) not null,
versionId bigint not null,
addedVersion int not null,
removedVersion int,
foreign key (clientId, addedVersion) references collectorVersions(clientId, id),
foreign key (clientId, removedVersion) references collectorVersions(clientId, id),
foreign key (clientId) references clients(clientId)
);
CREATE OR REPLACE FUNCTION removeMinTextVersion()
RETURNS TRIGGER AS $$
BEGIN
UPDATE collectorMinTextVersions
SET removedVersion = NEW.addedVersion
WHERE clientId = NEW.clientId and removedVersion is null;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER removeMinTextVersionTrigger
BEFORE INSERT ON collectorMinTextVersions
FOR EACH ROW
EXECUTE FUNCTION removeMinTextVersion();
CREATE TABLE collectorQueries (
id uuid primary key DEFAULT uuid_generate_v7(),
clientId varchar(255) not null,
name varchar(255) not null,
queryId uuid not null,
addedVersion int not null,
removedVersion int,
foreign key (queryId) references queries(queryId),
foreign key (clientId) references clients(clientId),
foreign key (clientId, addedVersion) references collectorVersions(clientId, id),
foreign key (clientId, removedVersion) references collectorVersions(clientId, id),
unique (clientId, name, removedVersion)
);
@@ -0,0 +1 @@
DROP TABLE documents;
@@ -0,0 +1,78 @@
CREATE TABLE documents (
id uuid primary key DEFAULT uuid_generate_v7(),
clientId varchar(255) not null,
hash text not null,
foreign key (clientId) references clients(clientId),
unique(clientId, hash)
);
CREATE TABLE documentUploads (
id uuid primary key DEFAULT uuid_generate_v7(),
bucket text not null,
key text not null,
clientId varchar(255) not null,
part unsignedsmallint not null,
createdAt timestamp not null,
foreign key (clientId) references clients(clientId)
);
CREATE TABLE documentEntries (
id uuid primary key DEFAULT uuid_generate_v7(),
documentId uuid not null,
bucket text not null,
key text not null,
foreign key (documentId) references documents(id)
);
CREATE TYPE cleanFailType AS ENUM (
'invalid_mimetype',
'invalid_read',
'invalid_read_pages',
'zero_page_count',
'large_file',
'small_dimensions',
'large_dimensions',
'small_dpi',
'large_dpi'
);
CREATE TYPE cleanMimeType AS ENUM ('application/pdf');
CREATE TABLE documentCleans (
id uuid primary key DEFAULT uuid_generate_v7(),
documentId uuid not null,
bucket text,
key text,
hash text,
mimetype cleanMimeType,
fail cleanFailType,
foreign key (documentId) references documents(id),
CONSTRAINT bucket_and_key_together CHECK ((bucket IS NULL) = (key IS NULL) and (bucket is null) = (mimetype is null) and (bucket is null) = (hash is null)),
CONSTRAINT location_xor_fail CHECK (
(bucket IS NOT NULL) != (fail IS NOT NULL)
)
);
CREATE TABLE documentCleanEntries (
id uuid primary key DEFAULT uuid_generate_v7(),
cleanId uuid not null,
version bigint not null,
foreign key (cleanId) references documentCleans(id)
);
CREATE TABLE documentTextExtractions (
id uuid primary key DEFAULT uuid_generate_v7(),
cleanId uuid not null,
bucket text not null,
key text not null,
hash text not null,
createdAt timestamp not null,
part unsignedsmallint not null,
foreign key (cleanId) references documentCleans(id)
);
CREATE TABLE documentTextExtractionEntries (
id uuid primary key DEFAULT uuid_generate_v7(),
textId uuid not null,
version bigint not null,
foreign key (textId) references documentTextExtractions(id)
);
@@ -1,31 +0,0 @@
-- Migration 006: Documents (DOWN)
-- Drop document clean entries first (depends on documentCleans)
DROP TABLE IF EXISTS documentCleanEntries;
-- Drop document cleans
DROP TABLE IF EXISTS documentCleans;
-- Drop document entries
DROP TABLE IF EXISTS documentEntries;
-- Drop documentUploads indexes
DROP INDEX IF EXISTS idx_documentuploads_folder_id;
DROP INDEX IF EXISTS idx_documentuploads_clientid;
DROP INDEX IF EXISTS idx_documentuploads_batch_id;
DROP INDEX IF EXISTS idx_documentuploads_filename;
-- Drop documentUploads table
DROP TABLE IF EXISTS documentUploads;
-- Drop documents indexes
DROP INDEX IF EXISTS idx_documents_folderid;
DROP INDEX IF EXISTS idx_documents_filename;
DROP INDEX IF EXISTS idx_documents_batch_id;
-- Drop documents table
DROP TABLE IF EXISTS documents;
-- Drop enums
DROP TYPE IF EXISTS cleanMimeType;
DROP TYPE IF EXISTS cleanFailType;
@@ -1,125 +0,0 @@
-- Migration 006: Documents (Consolidated)
-- Document storage and processing tables
-- Merges: 005_documents + 103 + 105 + 106 + 107 + 108 + 111 + 116 + 118
-- NOTE: documentTextExtractions and documentTextExtractionEntries removed (no longer used)
-- Enum for document clean failure types
CREATE TYPE cleanFailType AS ENUM (
'invalid_mimetype',
'invalid_read',
'invalid_read_pages',
'zero_page_count',
'large_file',
'small_dimensions',
'large_dimensions',
'small_dpi',
'large_dpi'
);
-- Enum for clean document mime types
CREATE TYPE cleanMimeType AS ENUM ('application/pdf');
-- Main documents table with all columns
CREATE TABLE documents (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
clientId varchar(255) NOT NULL,
hash text NOT NULL,
-- Batch reference (from migration 103)
batch_id uuid,
-- Filename (from migration 105)
filename TEXT,
-- Folder organization (from migration 111)
folderId uuid,
originalPath text,
-- File size (from migration 118)
file_size_bytes BIGINT,
FOREIGN KEY (clientId) REFERENCES clients(clientId),
FOREIGN KEY (batch_id) REFERENCES batch_uploads(id),
FOREIGN KEY (folderId) REFERENCES folders(id),
UNIQUE(clientId, hash)
);
-- Indexes for documents table
CREATE INDEX idx_documents_batch_id ON documents(batch_id);
CREATE INDEX idx_documents_filename ON documents(filename);
CREATE INDEX idx_documents_folderid ON documents(folderId);
-- Comments for immutable fields (from migration 111)
COMMENT ON COLUMN documents.originalPath IS
'Original path provided during upload. IMMUTABLE after creation - never modify this value.';
-- Document uploads table (staging area for incoming documents)
CREATE TABLE documentUploads (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
bucket text NOT NULL,
key text NOT NULL,
clientId varchar(255) NOT NULL,
part unsignedsmallint NOT NULL,
createdAt timestamp NOT NULL,
-- Filename (from migration 106)
filename TEXT,
-- Batch reference (from migration 107)
batch_id uuid,
-- Folder reference (from migration 116)
folder_id uuid,
FOREIGN KEY (clientId) REFERENCES clients(clientId),
FOREIGN KEY (folder_id) REFERENCES folders(id)
);
-- Indexes for documentUploads
CREATE INDEX idx_documentuploads_filename ON documentUploads(filename);
CREATE INDEX idx_documentuploads_batch_id ON documentUploads(batch_id);
CREATE INDEX idx_documentuploads_clientid ON documentUploads(clientId);
CREATE INDEX idx_documentuploads_folder_id ON documentUploads(folder_id);
-- Document entries (S3 storage records)
CREATE TABLE documentEntries (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
documentId uuid NOT NULL,
bucket text NOT NULL,
key text NOT NULL,
FOREIGN KEY (documentId) REFERENCES documents(id)
);
-- Comments for immutable fields (from migration 111)
COMMENT ON COLUMN documentEntries.key IS
'S3 object key. IMMUTABLE after creation - never modify this value.';
COMMENT ON COLUMN documentEntries.bucket IS
'S3 bucket name. IMMUTABLE after creation - never modify this value.';
-- Document cleans (processed/cleaned documents)
CREATE TABLE documentCleans (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
documentId uuid NOT NULL,
bucket text,
key text,
hash text,
mimetype cleanMimeType,
fail cleanFailType,
FOREIGN KEY (documentId) REFERENCES documents(id),
CONSTRAINT bucket_and_key_together CHECK (
(bucket IS NULL) = (key IS NULL) AND
(bucket IS NULL) = (mimetype IS NULL) AND
(bucket IS NULL) = (hash IS NULL)
),
CONSTRAINT location_xor_fail CHECK (
(bucket IS NOT NULL) != (fail IS NOT NULL)
)
);
-- Document clean entries (version tracking for cleans)
CREATE TABLE documentCleanEntries (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
cleanId uuid NOT NULL,
version bigint NOT NULL,
FOREIGN KEY (cleanId) REFERENCES documentCleans(id)
);
@@ -0,0 +1 @@
DROP TABLE results;
@@ -0,0 +1,18 @@
CREATE TABLE results (
id uuid primary key DEFAULT uuid_generate_v7(),
textEntryId uuid not null,
queryId uuid not null,
value TEXT not null,
queryVersion int not null,
foreign key (queryId) references queries(queryId),
foreign key (textEntryId) references documentTextExtractions(id),
foreign key (queryId, queryVersion) references queryVersions(queryId, versionId)
);
CREATE TABLE resultDependencies (
resultId uuid not null,
requiredResultId uuid not null,
foreign key (resultId) references results(id),
foreign key (requiredResultId) references results(id),
CONSTRAINT result_not_self_dependent CHECK (resultId != requiredResultId)
);
@@ -1,19 +0,0 @@
-- Migration 008: Field Extractions (DOWN)
-- Drop array fields table and indexes
DROP INDEX IF EXISTS idx_documentfieldextractionarrayfields_id_index;
DROP INDEX IF EXISTS idx_documentfieldextractionarrayfields_fieldextractionid;
DROP TABLE IF EXISTS documentFieldExtractionArrayFields;
-- Drop versions table and indexes
DROP INDEX IF EXISTS idx_unique_version_per_document;
DROP INDEX IF EXISTS idx_documentfieldextractionversions_documentid;
DROP INDEX IF EXISTS idx_documentfieldextractionversions_version;
DROP INDEX IF EXISTS idx_documentfieldextractionversions_fieldextractionid;
DROP TABLE IF EXISTS documentFieldExtractionVersions;
-- Drop main field extractions table and indexes
DROP INDEX IF EXISTS idx_documentfieldextractions_filename;
DROP INDEX IF EXISTS idx_documentfieldextractions_createdby;
DROP INDEX IF EXISTS idx_documentfieldextractions_documentid;
DROP TABLE IF EXISTS documentFieldExtractions;
@@ -1,6 +0,0 @@
-- Migration 010: Collector Views (DOWN)
DROP VIEW IF EXISTS fullActiveCollectors;
DROP VIEW IF EXISTS currentCollectorMinCleanVersions;
DROP VIEW IF EXISTS collectorLatestVersions;
DROP VIEW IF EXISTS collectorCurrentActiveVersions;
@@ -1,43 +0,0 @@
-- Migration 010: Collector Views (Simplified)
-- Views for collector configuration
-- NOTE: Query-related views and text version views removed (no longer used)
CREATE VIEW collectorCurrentActiveVersions AS
SELECT
c.clientId,
COALESCE(v.versionId, 0)::int AS activeVersion
FROM
clients c
LEFT JOIN (
SELECT DISTINCT ON (clientId)
clientId,
versionId
FROM
collectorActiveVersions
ORDER BY clientId, id DESC
) v ON c.clientId = v.clientId;
CREATE VIEW collectorLatestVersions AS
SELECT
j.clientId,
COALESCE(MAX(v.id), 0)::int AS latestVersion
FROM clients AS j
LEFT JOIN collectorVersions AS v ON v.clientId = j.clientId
GROUP BY j.clientId;
CREATE VIEW currentCollectorMinCleanVersions AS
SELECT DISTINCT
av.clientId,
COALESCE(ctv.versionId, 0) AS minCleanVersion
FROM collectorCurrentActiveVersions AS av
LEFT JOIN collectorMinCleanVersions AS ctv ON av.clientId = ctv.clientId
AND isInVersion(av.activeVersion, ctv.addedVersion, ctv.removedVersion);
-- Final fullActiveCollectors view (simplified without minTextVersion or fields)
CREATE VIEW fullActiveCollectors AS
SELECT DISTINCT av.clientId,
ccv.minCleanVersion,
av.activeVersion, lv.latestVersion
FROM collectorCurrentActiveVersions AS av
JOIN collectorLatestVersions AS lv ON lv.clientId = av.clientId
JOIN currentCollectorMinCleanVersions AS ccv ON av.clientId = ccv.clientId;
@@ -1,7 +0,0 @@
-- Migration 011: Document Views (DOWN)
DROP FUNCTION IF EXISTS listValidDocumentResults;
DROP VIEW IF EXISTS fullClients;
DROP VIEW IF EXISTS currentClientCanSync;
DROP VIEW IF EXISTS currentCleanEntries;
DROP FUNCTION IF EXISTS listDocumentIDs;
@@ -0,0 +1 @@
DROP VIEW fullActiveQueries;
@@ -0,0 +1,71 @@
CREATE VIEW queryCurrentActiveVersions as
SELECT DISTINCT
q.queryId,
coalesce(
(FIRST_VALUE(av.versionId) OVER (PARTITION BY q.queryId ORDER BY av.activeVersionEntryId DESC)),
0
)::int as activeVersion
FROM queries AS q
LEFT JOIN queryActiveVersions as av on av.queryId = q.queryId;
CREATE VIEW queryLatestVersions as
SELECT
q.queryId,
coalesce(max(v.versionId), 0)::int as latestVersion
FROM queries AS q
LEFT JOIN queryVersions as v on v.queryId = q.queryId
GROUP BY q.queryId;
CREATE VIEW queryCurrentConfigs as
SELECT av.queryId, c.config
FROM queryCurrentActiveVersions as av
LEFT JOIN queryConfigs AS c ON av.queryId = c.queryId
and isInVersion(av.activeVersion, c.addedVersion, c.removedVersion);
CREATE VIEW queryCurrentRequiredIds as
SELECT DISTINCT av.queryId, r.requiredQueryId
FROM queryCurrentActiveVersions as av
LEFT JOIN requiredQueries AS r ON av.queryId = r.queryId
and isInVersion(av.activeVersion, r.addedVersion, r.removedVersion);
CREATE VIEW queryCurrentRequiredIdsAGG as
SELECT queryId,
coalesce(
ARRAY_AGG(DISTINCT requiredQueryId)
FILTER (WHERE requiredQueryId != '00000000-0000-0000-0000-000000000000')::uuid[],
array[]::uuid[]
)::uuid[] as requiredIds
FROM queryCurrentRequiredIds
GROUP BY queryId;
CREATE VIEW fullActiveQueries AS
SELECT DISTINCT q.queryId, q.queryType, av.activeVersion, lv.latestVersion, c.config, r.requiredIds
FROM queries AS q
JOIN queryCurrentActiveVersions as av on q.queryId = av.queryId
JOIN queryLatestVersions as lv on lv.queryId = q.queryId
JOIN queryCurrentConfigs AS c ON q.queryId = c.queryId
JOIN queryCurrentRequiredIdsAGG AS r ON q.queryId = r.queryId;
CREATE VIEW queryActiveDependencies AS
WITH RECURSIVE queryActiveDependencies(queryId, requiredQueryId, path, cycle) AS (
SELECT
queryId,
requiredQueryId,
ARRAY[queryId, requiredQueryId]::uuid[] AS path,
false AS cycle
FROM queryCurrentRequiredIds
UNION ALL
SELECT
q.queryId,
qd.requiredQueryId,
path || qd.requiredQueryId,
qd.requiredQueryId = ANY(path) AS cycle
FROM queryCurrentRequiredIds as q
JOIN queryActiveDependencies as qd ON q.queryId = qd.requiredQueryId
WHERE NOT qd.cycle -- Stop if we detect a cycle
)
SELECT DISTINCT queryId as id, requiredQueryId
FROM queryActiveDependencies
WHERE NOT cycle;
@@ -0,0 +1,3 @@
DROP VIEW fullActiveCollectors;
DROP VIEW collectorQueryDependencyTree;
@@ -0,0 +1,123 @@
CREATE VIEW collectorCurrentActiveVersions AS
SELECT
c.clientId,
COALESCE(v.versionId, 0)::int AS activeVersion
FROM
clients c
LEFT JOIN (
SELECT DISTINCT ON (clientId)
clientId,
versionId
FROM
collectorActiveVersions
ORDER BY clientId, id DESC
) v ON c.clientId = v.clientId;
CREATE VIEW collectorLatestVersions as
SELECT
j.clientId,
coalesce(max(v.id), 0)::int as latestVersion
FROM clients as j
LEFT JOIN collectorVersions as v on v.clientId = j.clientId
GROUP BY j.clientId;
CREATE VIEW currentCollectorMinTextVersions as
SELECT DISTINCT
av.clientId,
coalesce(ctv.versionId, 0) as minTextVersion
FROM collectorCurrentActiveVersions as av
LEFT JOIN collectorMinTextVersions AS ctv ON av.clientId = ctv.clientId
and isInVersion(av.activeVersion, ctv.addedVersion, ctv.removedVersion);
CREATE VIEW currentCollectorMinCleanVersions as
SELECT DISTINCT
av.clientId,
coalesce(ctv.versionId, 0) as minCleanVersion
FROM collectorCurrentActiveVersions as av
LEFT JOIN collectorMinCleanVersions AS ctv ON av.clientId = ctv.clientId
and isInVersion(av.activeVersion, ctv.addedVersion, ctv.removedVersion);
CREATE VIEW currentCollectorQueries as
SELECT DISTINCT
av.clientId,
q.name,
q.queryId
FROM collectorCurrentActiveVersions as av
LEFT JOIN collectorQueries AS q ON av.clientId = q.clientId
and isInVersion(av.activeVersion, q.addedVersion, q.removedVersion);
CREATE VIEW currentCollectorQueriesJSONAGG as
SELECT DISTINCT
clientId,
jsonb_object_agg(name, queryId) FILTER (WHERE name is not null) AS fields
FROM currentCollectorQueries
GROUP BY clientId;
CREATE VIEW fullActiveCollectors AS
SELECT DISTINCT av.clientId,
ccv.minCleanVersion, ctv.minTextVersion,
av.activeVersion, lv.latestVersion,
q.fields
FROM collectorCurrentActiveVersions as av
JOIN collectorLatestVersions as lv on lv.clientId = av.clientId
JOIN currentCollectorMinCleanVersions AS ccv ON av.clientId = ccv.clientId
JOIN currentCollectorMinTextVersions AS ctv ON av.clientId = ctv.clientId
JOIN currentCollectorQueriesJSONAGG AS q ON av.clientId = q.clientId;
CREATE VIEW collectorQueryDependencyTree AS
WITH RECURSIVE collectorQueryDependencyTree AS (
SELECT cq.clientId, cq.queryId, ri.requiredIds
FROM currentCollectorQueries as cq
JOIN queryCurrentRequiredIdsAGG as ri on cq.queryId = ri.queryId
UNION ALL
SELECT acq.clientId, q.queryId, q.requiredIds
FROM queryCurrentRequiredIdsAGG as q
JOIN collectorQueryDependencyTree as acq on q.queryId = ANY(acq.requiredIds)
)
SELECT DISTINCT ct.clientId, ct.queryId, q.queryType, av.activeVersion as queryVersion, ct.requiredIds
FROM collectorQueryDependencyTree as ct
JOIN queryCurrentActiveVersions as av on ct.queryId = av.queryId
JOIN queries as q on q.queryId = ct.queryId;
CREATE OR REPLACE FUNCTION collectorQueryDependencyTreeByClient(
_clientId varchar(255)
)
RETURNS TABLE (
clientId varchar(255),
queryId uuid,
queryType queryType,
queryVersion int,
requiredIds uuid[]
) AS $$
BEGIN
RETURN QUERY
WITH clientQueries as (
SELECT q.clientId, q.queryId
FROM currentCollectorQueries as q
WHERE q.clientId = _clientId
),
dependencyTree as (
WITH RECURSIVE collectorQueryDependencyTree AS (
SELECT cq.clientId, cq.queryId, ri.requiredIds
FROM clientQueries as cq
JOIN queryCurrentRequiredIdsAGG as ri on cq.queryId = ri.queryId
UNION ALL
SELECT acq.clientId, q.queryId, q.requiredIds
FROM queryCurrentRequiredIdsAGG as q
JOIN collectorQueryDependencyTree as acq on q.queryId = ANY(acq.requiredIds)
)
SELECT DISTINCT ct.clientId, ct.queryId, q.queryType, av.activeVersion as queryVersion, ct.requiredIds
FROM collectorQueryDependencyTree as ct
JOIN queryCurrentActiveVersions as av on ct.queryId = av.queryId
JOIN queries as q on q.queryId = ct.queryId
)
SELECT t.clientId, t.queryId, t.queryType, t.queryVersion, t.requiredIds
FROM dependencyTree as t
WHERE t.clientID is not null;
END;
$$ LANGUAGE plpgsql;
@@ -0,0 +1 @@
DROP VIEW listDocumentIDs;
@@ -1,7 +1,3 @@
-- Migration 011: Document Views (Simplified)
-- Views and functions for document queries
-- NOTE: currentTextEntries and listValidDocumentResults removed (no longer used)
CREATE OR REPLACE FUNCTION listDocumentIDs(
_clientId varchar(255),
_batchSize INTEGER,
@@ -15,7 +11,7 @@ BEGIN
RETURN QUERY
SELECT d.id, totalCount
FROM documents AS d
FROM documents as d
WHERE d.clientId = _clientId
ORDER BY d.id
LIMIT _batchSize
@@ -23,7 +19,7 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
CREATE VIEW currentCleanEntries AS
CREATE VIEW currentCleanEntries as
WITH RankedExtractions AS (
SELECT
dc.id,
@@ -35,7 +31,7 @@ WITH RankedExtractions AS (
dc.hash,
dce.version,
d.clientId,
ROW_NUMBER() OVER (PARTITION BY dc.documentId ORDER BY dc.id DESC, dce.id DESC) AS row_num
ROW_NUMBER() OVER (PARTITION BY dc.documentId ORDER BY dc.id DESC, dce.id DESC) as row_num
FROM documents d
JOIN currentCollectorMinCleanVersions ccv ON d.clientId = ccv.clientId
JOIN documentCleans dc ON dc.documentId = d.id
@@ -55,30 +51,55 @@ SELECT
FROM RankedExtractions re
WHERE row_num = 1;
CREATE VIEW currentClientCanSync AS
CREATE VIEW currentTextEntries as
WITH RankedExtractions AS (
SELECT
extract.id,
cc.documentId,
extract.bucket,
extract.key,
extract.hash,
extract.cleanId,
dtee.version as extractionVersion,
ROW_NUMBER() OVER (PARTITION BY cc.documentId ORDER BY dtee.id DESC) as row_num
FROM documents d
JOIN currentCleanEntries cc on cc.documentId = d.id
JOIN currentCollectorMinTextVersions ctv ON ctv.clientId = d.clientId
JOIN documentTextExtractions extract ON extract.cleanId = cc.id
JOIN documentTextExtractionEntries dtee on dtee.textId = extract.id
AND dtee.version >= ctv.minTextVersion
)
SELECT
id,
documentId,
bucket,
key,
hash,
cleanId,
extractionVersion
FROM RankedExtractions
WHERE row_num = 1;
CREATE VIEW currentClientCanSync as
WITH RankedExtractions AS (
SELECT
ccs.clientId,
ccs.canSync,
ROW_NUMBER() OVER (PARTITION BY ccs.clientId ORDER BY ccs.syncId DESC) AS row_num
ROW_NUMBER() OVER (PARTITION BY ccs.clientId ORDER BY ccs.syncId DESC) as row_num
FROM clients c
JOIN clientCanSync ccs ON c.clientId = ccs.clientId
JOIN clientCanSync ccs on c.clientId = ccs.clientId
)
SELECT
c.clientId,
COALESCE(r.canSync, false) AS canSync
coalesce(r.canSync, false) as canSync
FROM clients c
LEFT JOIN RankedExtractions r ON r.clientId = c.clientId AND r.row_num = 1;
LEFT JOIN RankedExtractions r on r.clientId = c.clientId and r.row_num = 1;
CREATE VIEW fullClients AS
CREATE VIEW fullClients as
SELECT c.clientId, c.name, cs.canSync
FROM clients AS c
JOIN currentClientCanSync AS cs ON cs.clientId = c.clientId;
FROM clients as c
JOIN currentClientCanSync as cs on cs.clientId = c.clientId;
-- NOTE: This function exists for schema compatibility with original migrations.
-- It references tables/functions that no longer exist (results, resultDependencies,
-- collectorQueryDependencyTreeByClient, currentTextEntries) and will fail if called.
-- It was created in original migration 102 but never explicitly dropped.
CREATE OR REPLACE FUNCTION listValidDocumentResults(doc_id uuid)
RETURNS TABLE (documentId uuid, queryId uuid, resultId uuid, value text) AS $$
DECLARE
@@ -0,0 +1,13 @@
-- Drop indexes
DROP INDEX IF EXISTS idx_documents_batch_id;
DROP INDEX IF EXISTS idx_batch_uploads_status;
DROP INDEX IF EXISTS idx_batch_uploads_client_id;
-- Remove batch_id from documents table
ALTER TABLE documents DROP COLUMN IF EXISTS batch_id;
-- Drop batch uploads table
DROP TABLE IF EXISTS batch_uploads;
-- Drop batch status ENUM type
DROP TYPE IF EXISTS batch_status;
@@ -1,7 +1,3 @@
-- Migration 004: Batch Uploads
-- Batch upload tracking for ZIP file uploads
-- Merges original migrations 103 + 104
-- Create batch status ENUM type
CREATE TYPE batch_status AS ENUM (
'processing', -- Currently processing
@@ -10,7 +6,7 @@ CREATE TYPE batch_status AS ENUM (
'cancelled' -- Cancelled by user
);
-- Create batch uploads table with all columns
-- Create batch uploads table
CREATE TABLE batch_uploads (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
client_id varchar(255) NOT NULL,
@@ -33,20 +29,16 @@ CREATE TABLE batch_uploads (
created_at timestamp NOT NULL DEFAULT NOW(),
completed_at timestamp,
-- Storage metadata (from migration 104)
archive_bucket text,
archive_key text,
file_size_bytes bigint,
FOREIGN KEY (client_id) REFERENCES clients(clientId),
-- Constraint: storage metadata consistency
CONSTRAINT batch_storage_consistent CHECK (
(archive_bucket IS NULL AND archive_key IS NULL AND file_size_bytes IS NULL) OR
(archive_bucket IS NOT NULL AND archive_key IS NOT NULL)
)
FOREIGN KEY (client_id) REFERENCES clients(clientId)
);
-- Create indexes for efficient queries
CREATE INDEX idx_batch_uploads_client_id ON batch_uploads(client_id);
CREATE INDEX idx_batch_uploads_status ON batch_uploads(status);
-- Add batch_id to documents table
ALTER TABLE documents ADD COLUMN batch_id uuid NULL;
ALTER TABLE documents ADD FOREIGN KEY (batch_id) REFERENCES batch_uploads(id);
-- Create index on batch_id for efficient batch document queries
CREATE INDEX idx_documents_batch_id ON documents(batch_id);
@@ -0,0 +1,5 @@
-- Remove storage columns and constraint
ALTER TABLE batch_uploads DROP CONSTRAINT IF EXISTS batch_storage_required;
ALTER TABLE batch_uploads DROP COLUMN IF EXISTS file_size_bytes;
ALTER TABLE batch_uploads DROP COLUMN IF EXISTS archive_key;
ALTER TABLE batch_uploads DROP COLUMN IF EXISTS archive_bucket;
@@ -0,0 +1,11 @@
-- Add storage metadata columns to batch_uploads table
ALTER TABLE batch_uploads ADD COLUMN archive_bucket text;
ALTER TABLE batch_uploads ADD COLUMN archive_key text;
ALTER TABLE batch_uploads ADD COLUMN file_size_bytes bigint;
-- Add constraint to ensure storage metadata is consistent (if any storage field is set, bucket and key must both be set)
ALTER TABLE batch_uploads ADD CONSTRAINT batch_storage_consistent
CHECK (
(archive_bucket IS NULL AND archive_key IS NULL AND file_size_bytes IS NULL) OR
(archive_bucket IS NOT NULL AND archive_key IS NOT NULL)
);
@@ -0,0 +1,3 @@
-- Remove filename column and index
DROP INDEX IF EXISTS idx_documents_filename;
ALTER TABLE documents DROP COLUMN IF EXISTS filename;
@@ -0,0 +1,5 @@
-- Add filename column to documents table to store original filename with path
ALTER TABLE documents ADD COLUMN filename TEXT;
-- Add index for efficient filename searches
CREATE INDEX idx_documents_filename ON documents(filename);
@@ -0,0 +1,2 @@
DROP INDEX IF EXISTS idx_documentuploads_filename;
ALTER TABLE documentUploads DROP COLUMN IF EXISTS filename;
@@ -0,0 +1,2 @@
ALTER TABLE documentUploads ADD COLUMN filename TEXT;
CREATE INDEX idx_documentuploads_filename ON documentUploads(filename);
@@ -0,0 +1,2 @@
DROP INDEX IF EXISTS idx_documentuploads_batch_id;
ALTER TABLE documentUploads DROP COLUMN IF EXISTS batch_id;
@@ -0,0 +1,2 @@
ALTER TABLE documentUploads ADD COLUMN batch_id uuid;
CREATE INDEX idx_documentuploads_batch_id ON documentUploads(batch_id);
@@ -0,0 +1 @@
DROP INDEX IF EXISTS idx_documentuploads_clientid;
@@ -0,0 +1 @@
CREATE INDEX idx_documentuploads_clientid ON documentUploads(clientId);
@@ -1,5 +1,4 @@
-- Migration 005: Folders (DOWN)
-- Rollback: Drop folders table and its indexes
DROP INDEX IF EXISTS idx_folders_path;
DROP INDEX IF EXISTS idx_folders_clientid;
DROP INDEX IF EXISTS idx_folders_parentid;
@@ -1,6 +1,4 @@
-- Migration 005: Folders
-- Virtual folder hierarchy for document organization
-- Create folders table for hierarchical document organization
CREATE TABLE folders (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
path text NOT NULL,
@@ -18,9 +16,3 @@ CREATE TABLE folders (
CREATE INDEX idx_folders_parentid ON folders(parentId);
CREATE INDEX idx_folders_clientid ON folders(clientId);
CREATE INDEX idx_folders_path ON folders(path);
-- Add comment to clarify that folders are virtual (database-only, no S3 relationship)
COMMENT ON TABLE folders IS
'Virtual folder hierarchy for document organization. Database-only - has no direct relationship to S3 storage locations.';
COMMENT ON COLUMN folders.path IS
'Virtual folder path (e.g., "/contracts/2025"). Can be renamed without affecting S3 storage.';
@@ -1,5 +1,4 @@
-- Migration 007: Labels (DOWN)
-- Rollback: Drop documentLabels and labels tables with indexes
DROP INDEX IF EXISTS idx_documentlabels_document_label_time;
DROP INDEX IF EXISTS idx_documentlabels_appliedat;
DROP INDEX IF EXISTS idx_documentlabels_label;
@@ -1,6 +1,3 @@
-- Migration 007: Labels
-- Document labeling system for tracking processing status
-- Create labels lookup table
CREATE TABLE labels (
label text PRIMARY KEY,
@@ -0,0 +1,18 @@
-- Rollback: Remove folderId, originalPath columns and related constraints/indexes from documents table
-- Remove comments from folders table
COMMENT ON COLUMN folders.path IS NULL;
COMMENT ON TABLE folders IS NULL;
-- Remove comments from documentEntries table
COMMENT ON COLUMN documentEntries.bucket IS NULL;
COMMENT ON COLUMN documentEntries.key IS NULL;
-- Remove originalPath column
COMMENT ON COLUMN documents.originalPath IS NULL;
ALTER TABLE documents DROP COLUMN IF EXISTS originalPath;
-- Remove folderId column
DROP INDEX IF EXISTS idx_documents_folderid;
ALTER TABLE documents DROP CONSTRAINT IF EXISTS fk_documents_folderid;
ALTER TABLE documents DROP COLUMN IF EXISTS folderId;
@@ -0,0 +1,29 @@
-- Add folderId column to documents table for folder organization
-- Note: filename column already exists from migration 105
ALTER TABLE documents ADD COLUMN folderId uuid;
-- Add foreign key constraint to folders table
ALTER TABLE documents ADD CONSTRAINT fk_documents_folderid
FOREIGN KEY (folderId) REFERENCES folders(id);
-- Add index for efficient folder-based document queries
CREATE INDEX idx_documents_folderid ON documents(folderId);
-- Add originalPath column to store the exact path provided during upload
-- This value is IMMUTABLE after creation - it preserves the original upload path
-- even if the document is later moved to a different virtual folder
ALTER TABLE documents ADD COLUMN originalPath text;
COMMENT ON COLUMN documents.originalPath IS
'Original path provided during upload. IMMUTABLE after creation - never modify this value.';
-- Add comments to clarify immutability of S3 storage fields
COMMENT ON COLUMN documentEntries.key IS
'S3 object key. IMMUTABLE after creation - never modify this value.';
COMMENT ON COLUMN documentEntries.bucket IS
'S3 bucket name. IMMUTABLE after creation - never modify this value.';
-- Add comment to clarify that folders are virtual (database-only, no S3 relationship)
COMMENT ON TABLE folders IS
'Virtual folder hierarchy for document organization. Database-only - has no direct relationship to S3 storage locations.';
COMMENT ON COLUMN folders.path IS
'Virtual folder path (e.g., "/contracts/2025"). Can be renamed without affecting S3 storage.';
@@ -0,0 +1,5 @@
-- Rollback: Drop documentFieldExtractions table and its indexes
DROP INDEX IF EXISTS idx_documentfieldextractions_filename;
DROP INDEX IF EXISTS idx_documentfieldextractions_createdby;
DROP INDEX IF EXISTS idx_documentfieldextractions_documentid;
DROP TABLE IF EXISTS documentFieldExtractions;
@@ -0,0 +1,48 @@
-- Create documentFieldExtractions table for single-value fields
CREATE TABLE documentFieldExtractions (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
documentId uuid NOT NULL,
-- Single-value fields (19 fields total - 1:1 relationship)
-- Document identification
fileName text,
contractTitle text,
aareteDerivedAmendmentNum int,
-- Party information
clientName text,
payerName text,
payerState text,
providerState text,
-- Tax identification numbers (stored as text to preserve leading zeros)
filenameTin text,
provGroupTin text,
provGroupNpi text,
provGroupNameFull text,
provOtherTin text,
provOtherNpi text,
provOtherNameFull text,
-- Contract dates
aareteDerivedEffectiveDt date,
aareteDerivedTerminationDt date,
-- Renewal information
autoRenewalInd boolean,
autoRenewalTerm text,
-- Metadata
createdAt timestamp NOT NULL DEFAULT NOW(),
createdBy varchar(255) NOT NULL,
FOREIGN KEY (documentId) REFERENCES documents(id)
);
-- Indexes for efficient queries
CREATE INDEX idx_documentfieldextractions_documentid
ON documentFieldExtractions(documentId);
CREATE INDEX idx_documentfieldextractions_createdby
ON documentFieldExtractions(createdBy);
CREATE INDEX idx_documentfieldextractions_filename
ON documentFieldExtractions(fileName);
@@ -0,0 +1,4 @@
-- Rollback: Drop documentFieldExtractionVersions table and its indexes
DROP INDEX IF EXISTS idx_documentfieldextractionversions_version;
DROP INDEX IF EXISTS idx_documentfieldextractionversions_fieldextractionid;
DROP TABLE IF EXISTS documentFieldExtractionVersions;
@@ -0,0 +1,16 @@
-- Create documentFieldExtractionVersions table for version tracking
CREATE TABLE documentFieldExtractionVersions (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
fieldExtractionId uuid NOT NULL,
version bigint NOT NULL,
createdBy varchar(255) NOT NULL,
createdAt timestamp NOT NULL DEFAULT NOW(),
FOREIGN KEY (fieldExtractionId) REFERENCES documentFieldExtractions(id)
);
-- Indexes for version queries
CREATE INDEX idx_documentfieldextractionversions_fieldextractionid
ON documentFieldExtractionVersions(fieldExtractionId);
CREATE INDEX idx_documentfieldextractionversions_version
ON documentFieldExtractionVersions(version);
@@ -0,0 +1,4 @@
-- Rollback: Drop documentFieldExtractionArrayFields table and its indexes
DROP INDEX IF EXISTS idx_documentfieldextractionarrayfields_id_index;
DROP INDEX IF EXISTS idx_documentfieldextractionarrayfields_fieldextractionid;
DROP TABLE IF EXISTS documentFieldExtractionArrayFields;
@@ -1,84 +1,3 @@
-- Migration 008: Field Extractions (Consolidated)
-- Document field extraction storage for GenAI-extracted data
-- Merges: 112 + 113 + 114 + 117
-- Create documentFieldExtractions table for single-value fields
CREATE TABLE documentFieldExtractions (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
documentId uuid NOT NULL,
-- Single-value fields (19 fields total - 1:1 relationship)
-- Document identification
fileName text,
contractTitle text,
aareteDerivedAmendmentNum int,
-- Party information
clientName text,
payerName text,
payerState text,
providerState text,
-- Tax identification numbers (stored as text to preserve leading zeros)
filenameTin text,
provGroupTin text,
provGroupNpi text,
provGroupNameFull text,
provOtherTin text,
provOtherNpi text,
provOtherNameFull text,
-- Contract dates
aareteDerivedEffectiveDt date,
aareteDerivedTerminationDt date,
-- Renewal information
autoRenewalInd boolean,
autoRenewalTerm text,
-- Metadata
createdAt timestamp NOT NULL DEFAULT NOW(),
createdBy varchar(255) NOT NULL,
FOREIGN KEY (documentId) REFERENCES documents(id)
);
-- Indexes for efficient queries
CREATE INDEX idx_documentfieldextractions_documentid
ON documentFieldExtractions(documentId);
CREATE INDEX idx_documentfieldextractions_createdby
ON documentFieldExtractions(createdBy);
CREATE INDEX idx_documentfieldextractions_filename
ON documentFieldExtractions(fileName);
-- Create documentFieldExtractionVersions table for version tracking
-- Includes documentId column from migration 117 for unique constraint
CREATE TABLE documentFieldExtractionVersions (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
fieldExtractionId uuid NOT NULL,
version bigint NOT NULL,
createdBy varchar(255) NOT NULL,
createdAt timestamp NOT NULL DEFAULT NOW(),
-- documentId for unique version constraint (from migration 117)
documentId uuid NOT NULL,
FOREIGN KEY (fieldExtractionId) REFERENCES documentFieldExtractions(id),
FOREIGN KEY (documentId) REFERENCES documents(id)
);
-- Indexes for version queries
CREATE INDEX idx_documentfieldextractionversions_fieldextractionid
ON documentFieldExtractionVersions(fieldExtractionId);
CREATE INDEX idx_documentfieldextractionversions_version
ON documentFieldExtractionVersions(version);
CREATE INDEX idx_documentfieldextractionversions_documentid
ON documentFieldExtractionVersions(documentId);
-- Unique constraint to prevent duplicate versions per document (from migration 117)
CREATE UNIQUE INDEX idx_unique_version_per_document
ON documentFieldExtractionVersions(documentId, version);
-- Create documentFieldExtractionArrayFields table for 1:N array fields
CREATE TABLE documentFieldExtractionArrayFields (
id uuid PRIMARY KEY DEFAULT uuid_generate_v7(),
@@ -1,4 +1,3 @@
-- Migration 012: Field Extraction Views (DOWN)
-- Rollback: Drop field extraction views
DROP VIEW IF EXISTS currentFieldExtractionsWithArrayCount;
DROP VIEW IF EXISTS currentFieldExtractions;
@@ -1,6 +1,3 @@
-- Migration 012: Field Extraction Views
-- Views for querying current field extractions
-- Create view for current (newest) field extraction per document
CREATE VIEW currentFieldExtractions AS
SELECT DISTINCT ON (dfe.documentId)
@@ -36,12 +33,12 @@ ORDER BY dfe.documentId, dfev.id DESC;
CREATE VIEW currentFieldExtractionsWithArrayCount AS
SELECT
cfe.*,
COALESCE(array_counts.arraySize, 0) AS arraySize
COALESCE(array_counts.arraySize, 0) as arraySize
FROM currentFieldExtractions cfe
LEFT JOIN (
SELECT
fieldExtractionId,
COUNT(*) AS arraySize
COUNT(*) as arraySize
FROM documentFieldExtractionArrayFields
GROUP BY fieldExtractionId
) array_counts ON array_counts.fieldExtractionId = cfe.id;
@@ -0,0 +1,4 @@
-- Remove folder_id column from documentUploads table
DROP INDEX IF EXISTS idx_documentuploads_folder_id;
ALTER TABLE documentUploads DROP CONSTRAINT IF EXISTS fk_documentuploads_folder_id;
ALTER TABLE documentUploads DROP COLUMN IF EXISTS folder_id;
@@ -0,0 +1,6 @@
-- Add folder_id column to documentUploads table to persist folder association during batch uploads
ALTER TABLE documentUploads ADD COLUMN folder_id uuid;
-- Add foreign key constraint referencing folders table
ALTER TABLE documentUploads ADD CONSTRAINT fk_documentuploads_folder_id FOREIGN KEY (folder_id) REFERENCES folders(id);
-- Add index for efficient lookup by folder
CREATE INDEX idx_documentuploads_folder_id ON documentUploads(folder_id);
@@ -0,0 +1,10 @@
-- Remove the unique constraint and documentId column
DROP INDEX IF EXISTS idx_documentfieldextractionversions_documentid;
DROP INDEX IF EXISTS idx_unique_version_per_document;
ALTER TABLE documentFieldExtractionVersions
DROP CONSTRAINT IF EXISTS fk_documentfieldextractionversions_documentid;
ALTER TABLE documentFieldExtractionVersions
DROP COLUMN IF EXISTS documentId;
@@ -0,0 +1,30 @@
-- Add unique constraint to prevent duplicate versions per document
-- This ensures that concurrent requests cannot create the same version number
-- First, add documentId column to versions table for easier constraint enforcement
ALTER TABLE documentFieldExtractionVersions
ADD COLUMN documentId uuid;
-- Populate documentId from the joined extraction record
UPDATE documentFieldExtractionVersions dfev
SET documentId = dfe.documentId
FROM documentFieldExtractions dfe
WHERE dfev.fieldExtractionId = dfe.id;
-- Make documentId NOT NULL after populating
ALTER TABLE documentFieldExtractionVersions
ALTER COLUMN documentId SET NOT NULL;
-- Add foreign key constraint (documents table has 'id' as primary key)
ALTER TABLE documentFieldExtractionVersions
ADD CONSTRAINT fk_documentfieldextractionversions_documentid
FOREIGN KEY (documentId) REFERENCES documents(id);
-- Add unique constraint on documentId + version
-- This prevents duplicate version numbers for the same document
CREATE UNIQUE INDEX idx_unique_version_per_document
ON documentFieldExtractionVersions(documentId, version);
-- Add index for efficient lookups by documentId
CREATE INDEX idx_documentfieldextractionversions_documentid
ON documentFieldExtractionVersions(documentId);
@@ -0,0 +1,2 @@
-- Remove file_size_bytes column from documents table
ALTER TABLE documents DROP COLUMN file_size_bytes;
@@ -0,0 +1,4 @@
-- Add file_size_bytes column to documents table
-- Stores the size of the document in bytes as measured from S3 HeadObject
-- NULL for legacy documents (before this feature was added)
ALTER TABLE documents ADD COLUMN file_size_bytes BIGINT;
@@ -0,0 +1,287 @@
-- Down migration to restore query functionality
-- This recreates all query-related tables, views, and functions
-- Drop the simplified fullActiveCollectors view
DROP VIEW IF EXISTS fullActiveCollectors;
-- Recreate query type enum
CREATE TYPE queryType AS ENUM ('context_full', 'json_extractor');
-- Recreate queries table
CREATE TABLE queries (
queryId uuid primary key DEFAULT uuid_generate_v7(),
queryType queryType not null
);
-- Recreate queryVersions table
CREATE TABLE queryVersions (
queryId uuid not null,
versionId int not null,
addedAt timestamp not null default current_timestamp,
primary key (versionId, queryId),
foreign key (queryId) references queries(queryId)
);
-- Recreate version number function and trigger
CREATE OR REPLACE FUNCTION setQueryVersionNumber()
RETURNS TRIGGER AS $$
BEGIN
SELECT COALESCE(MAX(versionId), 0) + 1
INTO NEW.versionId
FROM queryVersions
WHERE queryId = NEW.queryId;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER setQueryVersionNumberTrigger
BEFORE INSERT ON queryVersions
FOR EACH ROW
EXECUTE FUNCTION setQueryVersionNumber();
-- Recreate queryActiveVersions table
CREATE TABLE queryActiveVersions (
activeVersionEntryId uuid primary key DEFAULT uuid_generate_v7(),
queryId uuid not null,
versionId int not null,
foreign key (queryId, versionId) references queryVersions(queryId, versionId)
);
-- Recreate requiredQueries table
CREATE TABLE requiredQueries (
requiredQueryEntryId uuid primary key DEFAULT uuid_generate_v7(),
queryId uuid not null,
requiredQueryId uuid not null,
addedVersion int not null,
removedVersion int,
foreign key (queryId) references queries(queryId),
foreign key (requiredQueryId) references queries(queryId),
foreign key (queryId, addedVersion) references queryVersions(queryId, versionId),
foreign key (queryId, removedVersion) references queryVersions(queryId, versionId),
unique (queryId, requiredQueryId, removedVersion)
);
-- Recreate queryConfigs table
CREATE TABLE queryConfigs (
configId uuid primary key DEFAULT uuid_generate_v7(),
queryId uuid not null,
config jsonb not null,
addedVersion int not null,
removedVersion int,
foreign key (queryId) references queries(queryId),
foreign key (queryId, addedVersion) references queryVersions(queryId, versionId),
foreign key (queryId, removedVersion) references queryVersions(queryId, versionId),
unique (queryId, removedVersion)
);
-- Recreate removeQueryConfig function and trigger
CREATE OR REPLACE FUNCTION removeQueryConfig()
RETURNS TRIGGER AS $$
BEGIN
UPDATE queryConfigs
SET removedVersion = NEW.addedVersion
WHERE queryId = NEW.queryId and removedVersion is null;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER removeQueryConfigTrigger
BEFORE INSERT ON queryConfigs
FOR EACH ROW
EXECUTE FUNCTION removeQueryConfig();
-- Recreate collectorQueries table
CREATE TABLE collectorQueries (
id uuid primary key DEFAULT uuid_generate_v7(),
clientId varchar(255) not null,
name varchar(255) not null,
queryId uuid not null,
addedVersion int not null,
removedVersion int,
foreign key (queryId) references queries(queryId),
foreign key (clientId) references clients(clientId),
foreign key (clientId, addedVersion) references collectorVersions(clientId, id),
foreign key (clientId, removedVersion) references collectorVersions(clientId, id),
unique (clientId, name, removedVersion)
);
-- Recreate results table
CREATE TABLE results (
id uuid primary key DEFAULT uuid_generate_v7(),
textEntryId uuid not null,
queryId uuid not null,
value TEXT not null,
queryVersion int not null,
foreign key (queryId) references queries(queryId),
foreign key (textEntryId) references documentTextExtractions(id),
foreign key (queryId, queryVersion) references queryVersions(queryId, versionId)
);
-- Recreate resultDependencies table
CREATE TABLE resultDependencies (
resultId uuid not null,
requiredResultId uuid not null,
foreign key (resultId) references results(id),
foreign key (requiredResultId) references results(id),
CONSTRAINT result_not_self_dependent CHECK (resultId != requiredResultId)
);
-- Recreate query views
CREATE VIEW queryCurrentActiveVersions as
SELECT DISTINCT
q.queryId,
coalesce(
(FIRST_VALUE(av.versionId) OVER (PARTITION BY q.queryId ORDER BY av.activeVersionEntryId DESC)),
0
)::int as activeVersion
FROM queries AS q
LEFT JOIN queryActiveVersions as av on av.queryId = q.queryId;
CREATE VIEW queryLatestVersions as
SELECT
q.queryId,
coalesce(max(v.versionId), 0)::int as latestVersion
FROM queries AS q
LEFT JOIN queryVersions as v on v.queryId = q.queryId
GROUP BY q.queryId;
CREATE VIEW queryCurrentConfigs as
SELECT av.queryId, c.config
FROM queryCurrentActiveVersions as av
LEFT JOIN queryConfigs AS c ON av.queryId = c.queryId
and isInVersion(av.activeVersion, c.addedVersion, c.removedVersion);
CREATE VIEW queryCurrentRequiredIds as
SELECT DISTINCT av.queryId, r.requiredQueryId
FROM queryCurrentActiveVersions as av
LEFT JOIN requiredQueries AS r ON av.queryId = r.queryId
and isInVersion(av.activeVersion, r.addedVersion, r.removedVersion);
CREATE VIEW queryCurrentRequiredIdsAGG as
SELECT queryId,
coalesce(
ARRAY_AGG(DISTINCT requiredQueryId)
FILTER (WHERE requiredQueryId != '00000000-0000-0000-0000-000000000000')::uuid[],
array[]::uuid[]
)::uuid[] as requiredIds
FROM queryCurrentRequiredIds
GROUP BY queryId;
CREATE VIEW fullActiveQueries AS
SELECT DISTINCT q.queryId, q.queryType, av.activeVersion, lv.latestVersion, c.config, r.requiredIds
FROM queries AS q
JOIN queryCurrentActiveVersions as av on q.queryId = av.queryId
JOIN queryLatestVersions as lv on lv.queryId = q.queryId
JOIN queryCurrentConfigs AS c ON q.queryId = c.queryId
JOIN queryCurrentRequiredIdsAGG AS r ON q.queryId = r.queryId;
CREATE VIEW queryActiveDependencies AS
WITH RECURSIVE queryActiveDependencies(queryId, requiredQueryId, path, cycle) AS (
SELECT
queryId,
requiredQueryId,
ARRAY[queryId, requiredQueryId]::uuid[] AS path,
false AS cycle
FROM queryCurrentRequiredIds
UNION ALL
SELECT
q.queryId,
qd.requiredQueryId,
path || qd.requiredQueryId,
qd.requiredQueryId = ANY(path) AS cycle
FROM queryCurrentRequiredIds as q
JOIN queryActiveDependencies as qd ON q.queryId = qd.requiredQueryId
WHERE NOT qd.cycle
)
SELECT DISTINCT queryId as id, requiredQueryId
FROM queryActiveDependencies
WHERE NOT cycle;
-- Recreate collector views that depend on queries
CREATE VIEW currentCollectorQueries as
SELECT DISTINCT
av.clientId,
q.name,
q.queryId
FROM collectorCurrentActiveVersions as av
LEFT JOIN collectorQueries AS q ON av.clientId = q.clientId
and isInVersion(av.activeVersion, q.addedVersion, q.removedVersion);
CREATE VIEW currentCollectorQueriesJSONAGG as
SELECT DISTINCT
clientId,
jsonb_object_agg(name, queryId) FILTER (WHERE name is not null) AS fields
FROM currentCollectorQueries
GROUP BY clientId;
CREATE VIEW fullActiveCollectors AS
SELECT DISTINCT av.clientId,
ccv.minCleanVersion, ctv.minTextVersion,
av.activeVersion, lv.latestVersion,
q.fields
FROM collectorCurrentActiveVersions as av
JOIN collectorLatestVersions as lv on lv.clientId = av.clientId
JOIN currentCollectorMinCleanVersions AS ccv ON av.clientId = ccv.clientId
JOIN currentCollectorMinTextVersions AS ctv ON av.clientId = ctv.clientId
JOIN currentCollectorQueriesJSONAGG AS q ON av.clientId = q.clientId;
CREATE VIEW collectorQueryDependencyTree AS
WITH RECURSIVE collectorQueryDependencyTree AS (
SELECT cq.clientId, cq.queryId, ri.requiredIds
FROM currentCollectorQueries as cq
JOIN queryCurrentRequiredIdsAGG as ri on cq.queryId = ri.queryId
UNION ALL
SELECT acq.clientId, q.queryId, q.requiredIds
FROM queryCurrentRequiredIdsAGG as q
JOIN collectorQueryDependencyTree as acq on q.queryId = ANY(acq.requiredIds)
)
SELECT DISTINCT ct.clientId, ct.queryId, q.queryType, av.activeVersion as queryVersion, ct.requiredIds
FROM collectorQueryDependencyTree as ct
JOIN queryCurrentActiveVersions as av on ct.queryId = av.queryId
JOIN queries as q on q.queryId = ct.queryId;
CREATE OR REPLACE FUNCTION collectorQueryDependencyTreeByClient(
_clientId varchar(255)
)
RETURNS TABLE (
clientId varchar(255),
queryId uuid,
queryType queryType,
queryVersion int,
requiredIds uuid[]
) AS $$
BEGIN
RETURN QUERY
WITH clientQueries as (
SELECT q.clientId, q.queryId
FROM currentCollectorQueries as q
WHERE q.clientId = _clientId
),
dependencyTree as (
WITH RECURSIVE collectorQueryDependencyTree AS (
SELECT cq.clientId, cq.queryId, ri.requiredIds
FROM clientQueries as cq
JOIN queryCurrentRequiredIdsAGG as ri on cq.queryId = ri.queryId
UNION ALL
SELECT acq.clientId, q.queryId, q.requiredIds
FROM queryCurrentRequiredIdsAGG as q
JOIN collectorQueryDependencyTree as acq on q.queryId = ANY(acq.requiredIds)
)
SELECT DISTINCT ct.clientId, ct.queryId, q.queryType, av.activeVersion as queryVersion, ct.requiredIds
FROM collectorQueryDependencyTree as ct
JOIN queryCurrentActiveVersions as av on ct.queryId = av.queryId
JOIN queries as q on q.queryId = ct.queryId
)
SELECT t.clientId, t.queryId, t.queryType, t.queryVersion, t.requiredIds
FROM dependencyTree as t
WHERE t.clientID is not null;
END;
$$ LANGUAGE plpgsql;
@@ -0,0 +1,53 @@
-- Migration to remove query functionality from the database
-- This drops all query-related tables, views, and functions
-- First drop the function that depends on query views
DROP FUNCTION IF EXISTS collectorQueryDependencyTreeByClient;
-- Drop the collector views that depend on query tables (in order of dependencies)
DROP VIEW IF EXISTS collectorQueryDependencyTree;
DROP VIEW IF EXISTS fullActiveCollectors;
DROP VIEW IF EXISTS currentCollectorQueriesJSONAGG;
DROP VIEW IF EXISTS currentCollectorQueries;
-- Drop query views (in order of dependencies)
DROP VIEW IF EXISTS fullActiveQueries;
DROP VIEW IF EXISTS queryActiveDependencies;
DROP VIEW IF EXISTS queryCurrentRequiredIdsAGG;
DROP VIEW IF EXISTS queryCurrentRequiredIds;
DROP VIEW IF EXISTS queryCurrentConfigs;
DROP VIEW IF EXISTS queryLatestVersions;
DROP VIEW IF EXISTS queryCurrentActiveVersions;
-- Drop result tables
DROP TABLE IF EXISTS resultDependencies;
DROP TABLE IF EXISTS results;
-- Drop collectorQueries table (links collectors to queries)
DROP TABLE IF EXISTS collectorQueries;
-- Drop query configuration and dependency tables
DROP TABLE IF EXISTS queryConfigs;
DROP TABLE IF EXISTS requiredQueries;
DROP TABLE IF EXISTS queryActiveVersions;
DROP TABLE IF EXISTS queryVersions;
DROP TABLE IF EXISTS queries;
-- Drop triggers and functions
DROP TRIGGER IF EXISTS setQueryVersionNumberTrigger ON queryVersions;
DROP FUNCTION IF EXISTS setQueryVersionNumber;
DROP TRIGGER IF EXISTS removeQueryConfigTrigger ON queryConfigs;
DROP FUNCTION IF EXISTS removeQueryConfig;
-- Drop the query type enum
DROP TYPE IF EXISTS queryType;
-- Recreate the fullActiveCollectors view without the fields column
CREATE VIEW fullActiveCollectors AS
SELECT DISTINCT av.clientId,
ccv.minCleanVersion, ctv.minTextVersion,
av.activeVersion, lv.latestVersion
FROM collectorCurrentActiveVersions as av
JOIN collectorLatestVersions as lv on lv.clientId = av.clientId
JOIN currentCollectorMinCleanVersions AS ccv ON av.clientId = ccv.clientId
JOIN currentCollectorMinTextVersions AS ctv ON av.clientId = ctv.clientId;
@@ -1,2 +0,0 @@
-- Stub migration for version compatibility
-- No actual changes needed.
@@ -1,4 +0,0 @@
-- Stub migration for version compatibility
-- This file exists to satisfy the migrate tool for databases that were
-- previously at version 119 (before migration collapse).
-- No actual changes - the schema is already correct.
@@ -0,0 +1,104 @@
-- Rollback migration to restore text extraction functionality
-- NOTE: This recreates text extraction tables and views
-- First drop the simplified fullActiveCollectors view
DROP VIEW IF EXISTS fullActiveCollectors;
-- Recreate documentTextExtractions table
CREATE TABLE documentTextExtractions (
id uuid primary key DEFAULT uuid_generate_v7(),
cleanId uuid not null,
bucket text not null,
key text not null,
hash text not null,
createdAt timestamp not null,
part unsignedsmallint not null,
foreign key (cleanId) references documentCleans(id)
);
-- Recreate documentTextExtractionEntries table
CREATE TABLE documentTextExtractionEntries (
id uuid primary key DEFAULT uuid_generate_v7(),
textId uuid not null,
version bigint not null,
foreign key (textId) references documentTextExtractions(id)
);
-- Recreate collectorMinTextVersions table
CREATE TABLE collectorMinTextVersions (
id uuid primary key DEFAULT uuid_generate_v7(),
clientId varchar(255) not null,
versionId bigint not null,
addedVersion int not null,
removedVersion int,
foreign key (clientId, addedVersion) references collectorVersions(clientId, id),
foreign key (clientId, removedVersion) references collectorVersions(clientId, id),
foreign key (clientId) references clients(clientId)
);
-- Recreate removeMinTextVersion function
CREATE OR REPLACE FUNCTION removeMinTextVersion()
RETURNS TRIGGER AS $$
BEGIN
UPDATE collectorMinTextVersions
SET removedVersion = NEW.addedVersion
WHERE clientId = NEW.clientId and removedVersion is null;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Recreate trigger for collectorMinTextVersions
CREATE TRIGGER removeMinTextVersionTrigger
BEFORE INSERT ON collectorMinTextVersions
FOR EACH ROW
EXECUTE FUNCTION removeMinTextVersion();
-- Recreate currentCollectorMinTextVersions view
CREATE VIEW currentCollectorMinTextVersions as
SELECT DISTINCT
av.clientId,
coalesce(ctv.versionId, 0) as minTextVersion
FROM collectorCurrentActiveVersions as av
LEFT JOIN collectorMinTextVersions AS ctv ON av.clientId = ctv.clientId
and isInVersion(av.activeVersion, ctv.addedVersion, ctv.removedVersion);
-- Recreate fullActiveCollectors view with minTextVersion
CREATE VIEW fullActiveCollectors AS
SELECT DISTINCT av.clientId,
ccv.minCleanVersion, ctv.minTextVersion,
av.activeVersion, lv.latestVersion
FROM collectorCurrentActiveVersions as av
JOIN collectorLatestVersions as lv on lv.clientId = av.clientId
JOIN currentCollectorMinCleanVersions AS ccv ON av.clientId = ccv.clientId
JOIN currentCollectorMinTextVersions AS ctv ON av.clientId = ctv.clientId;
-- Recreate currentTextEntries view
CREATE VIEW currentTextEntries as
WITH RankedExtractions AS (
SELECT
extract.id,
cc.documentId,
extract.bucket,
extract.key,
extract.hash,
extract.cleanId,
dtee.version as extractionVersion,
ROW_NUMBER() OVER (PARTITION BY cc.documentId ORDER BY dtee.id DESC) as row_num
FROM documents d
JOIN currentCleanEntries cc on cc.documentId = d.id
JOIN currentCollectorMinTextVersions ctv ON ctv.clientId = d.clientId
JOIN documentTextExtractions extract ON extract.cleanId = cc.id
JOIN documentTextExtractionEntries dtee on dtee.textId = extract.id
AND dtee.version >= ctv.minTextVersion
)
SELECT
id,
documentId,
bucket,
key,
hash,
cleanId,
extractionVersion
FROM RankedExtractions
WHERE row_num = 1;
@@ -0,0 +1,32 @@
-- Migration to remove text extraction functionality from the database
-- This drops all text extraction related tables, views, and functions
-- NOTE: Field extractions are separate and NOT affected by this migration
-- First drop the view that depends on text extraction tables
DROP VIEW IF EXISTS currentTextEntries;
-- Drop fullActiveCollectors view that depends on currentCollectorMinTextVersions
DROP VIEW IF EXISTS fullActiveCollectors;
-- Drop the currentCollectorMinTextVersions view
DROP VIEW IF EXISTS currentCollectorMinTextVersions;
-- Drop the trigger and function for collectorMinTextVersions
DROP TRIGGER IF EXISTS removeMinTextVersionTrigger ON collectorMinTextVersions;
DROP FUNCTION IF EXISTS removeMinTextVersion;
-- Drop the collectorMinTextVersions table
DROP TABLE IF EXISTS collectorMinTextVersions;
-- Drop the text extraction tables (child first for FK constraints)
DROP TABLE IF EXISTS documentTextExtractionEntries;
DROP TABLE IF EXISTS documentTextExtractions;
-- Recreate fullActiveCollectors view WITHOUT minTextVersion
CREATE VIEW fullActiveCollectors AS
SELECT DISTINCT av.clientId,
ccv.minCleanVersion,
av.activeVersion, lv.latestVersion
FROM collectorCurrentActiveVersions as av
JOIN collectorLatestVersions as lv on lv.clientId = av.clientId
JOIN currentCollectorMinCleanVersions AS ccv ON av.clientId = ccv.clientId;
@@ -1,2 +0,0 @@
-- Stub migration for version compatibility
-- No actual changes needed.
@@ -1,4 +0,0 @@
-- Stub migration for version compatibility
-- This file exists to satisfy the migrate tool for databases that were
-- previously at version 120 (before migration collapse).
-- No actual changes - the schema is already correct.