-- 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;