diff --git a/__fixtures__/seed/README.md b/__fixtures__/seed/README.md index 96839ec0a..3f1a359a2 100644 --- a/__fixtures__/seed/README.md +++ b/__fixtures__/seed/README.md @@ -17,7 +17,7 @@ Composable SQL seed layers for integration testing. Each layer builds on the pre import { getConnections } from 'pgsql-test'; import path from 'path'; -const SEED = path.resolve(__dirname, '../../../../__fixtures__/seed'); +const SEED = path.resolve(__dirname, '../../../__fixtures__/seed'); const { db, teardown } = await getConnections({ seed: seed.sqlfile([ @@ -37,6 +37,16 @@ Pick only the layers you need: - **Full stack with app data**: all four files in order - **Custom app schema**: `services/setup.sql` + `services/test-data.sql` + your own schema/data SQL +## Consumers + +These test files use the shared fixtures (no local duplicates): + +| Test file | Seed files used | +|-----------|----------------| +| `graphql/server-test/__tests__/server.integration.test.ts` | `services/*` + `app-schemas/simple-pets/*` (services scenarios) | +| `graphql/server-test/__tests__/express-context.integration.test.ts` | `services/*` + `app-schemas/simple-pets/*` | +| `graphql/server-test/__tests__/upload.integration.test.ts` | `services/setup.sql` (DDL only, storage data is local) | + ## Well-Known IDs | Entity | ID | Notes | diff --git a/graphql/server-test/__fixtures__/seed/simple-seed-services/schema.sql b/graphql/server-test/__fixtures__/seed/simple-seed-services/schema.sql deleted file mode 100644 index 25e55f8fe..000000000 --- a/graphql/server-test/__fixtures__/seed/simple-seed-services/schema.sql +++ /dev/null @@ -1,65 +0,0 @@ --- Schema creation for simple-seed-services test scenario --- Creates the simple-pets schemas and animals table - --- Create schemas -CREATE SCHEMA IF NOT EXISTS "simple-pets-public"; -CREATE SCHEMA IF NOT EXISTS "simple-pets-private"; -CREATE SCHEMA IF NOT EXISTS "simple-pets-pets-public"; - --- Grant schema usage -GRANT USAGE ON SCHEMA "simple-pets-public" TO administrator, authenticated, anonymous; -GRANT USAGE ON SCHEMA "simple-pets-private" TO administrator, authenticated, anonymous; -GRANT USAGE ON SCHEMA "simple-pets-pets-public" TO administrator, authenticated, anonymous; - --- Set default privileges for simple-pets-public -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-public" - GRANT ALL ON TABLES TO administrator; -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-public" - GRANT USAGE ON SEQUENCES TO administrator, authenticated; -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-public" - GRANT ALL ON FUNCTIONS TO administrator, authenticated, anonymous; - --- Set default privileges for simple-pets-private -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-private" - GRANT ALL ON TABLES TO administrator; -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-private" - GRANT USAGE ON SEQUENCES TO administrator, authenticated; -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-private" - GRANT ALL ON FUNCTIONS TO administrator, authenticated, anonymous; - --- Set default privileges for simple-pets-pets-public -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-pets-public" - GRANT ALL ON TABLES TO administrator; -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-pets-public" - GRANT USAGE ON SEQUENCES TO administrator, authenticated; -ALTER DEFAULT PRIVILEGES IN SCHEMA "simple-pets-pets-public" - GRANT ALL ON FUNCTIONS TO administrator, authenticated, anonymous; - --- Create animals table -CREATE TABLE IF NOT EXISTS "simple-pets-pets-public".animals ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - name text NOT NULL, - species text NOT NULL, - owner_id uuid, - created_at timestamptz DEFAULT now(), - updated_at timestamptz DEFAULT now(), - CONSTRAINT animals_name_chk CHECK (character_length(name) <= 256), - CONSTRAINT animals_species_chk CHECK (character_length(species) <= 100) -); - --- Create timestamp trigger -DROP TRIGGER IF EXISTS timestamps_tg ON "simple-pets-pets-public".animals; -CREATE TRIGGER timestamps_tg - BEFORE INSERT OR UPDATE - ON "simple-pets-pets-public".animals - FOR EACH ROW - EXECUTE PROCEDURE stamps.timestamps(); - --- Create indexes -CREATE INDEX IF NOT EXISTS animals_created_at_idx ON "simple-pets-pets-public".animals (created_at); -CREATE INDEX IF NOT EXISTS animals_updated_at_idx ON "simple-pets-pets-public".animals (updated_at); - --- Grant table permissions (allow anonymous to do CRUD for tests) -GRANT SELECT, INSERT, UPDATE, DELETE ON "simple-pets-pets-public".animals TO administrator; -GRANT SELECT, INSERT, UPDATE, DELETE ON "simple-pets-pets-public".animals TO authenticated; -GRANT SELECT, INSERT, UPDATE, DELETE ON "simple-pets-pets-public".animals TO anonymous; diff --git a/graphql/server-test/__fixtures__/seed/simple-seed-services/setup.sql b/graphql/server-test/__fixtures__/seed/simple-seed-services/setup.sql deleted file mode 100644 index 96d047968..000000000 --- a/graphql/server-test/__fixtures__/seed/simple-seed-services/setup.sql +++ /dev/null @@ -1,346 +0,0 @@ --- Setup for simple-seed-services test scenario --- Creates the required schemas, extensions, and meta-schemas - --- Ensure uuid-ossp extension is available -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -CREATE EXTENSION IF NOT EXISTS "citext"; - --- Create uuid_nil function if not exists (returns the nil UUID) -CREATE OR REPLACE FUNCTION uuid_nil() RETURNS uuid AS $$ - SELECT '00000000-0000-0000-0000-000000000000'::uuid; -$$ LANGUAGE sql IMMUTABLE; - --- Create required roles if they don't exist -DO $$ -BEGIN - IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'administrator') THEN - CREATE ROLE administrator; - END IF; - IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticated') THEN - CREATE ROLE authenticated; - END IF; - IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'anonymous') THEN - CREATE ROLE anonymous; - END IF; - IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'app_user') THEN - CREATE ROLE app_user; - END IF; - IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'app_admin') THEN - CREATE ROLE app_admin; - END IF; -END -$$; - --- Create stamps schema for timestamp trigger if not exists -CREATE SCHEMA IF NOT EXISTS stamps; - --- Create timestamps trigger function -CREATE OR REPLACE FUNCTION stamps.timestamps() -RETURNS TRIGGER AS $$ -BEGIN - IF TG_OP = 'INSERT' THEN - NEW.created_at = COALESCE(NEW.created_at, now()); - END IF; - NEW.updated_at = now(); - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - --- Create hostname domain if it doesn't exist -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'hostname') THEN - CREATE DOMAIN hostname AS text; - END IF; -END -$$; - --- Create metaschema schemas -CREATE SCHEMA IF NOT EXISTS metaschema_public; -CREATE SCHEMA IF NOT EXISTS metaschema_modules_public; -CREATE SCHEMA IF NOT EXISTS services_public; - --- Grant schema usage -GRANT USAGE ON SCHEMA metaschema_public TO administrator, authenticated, anonymous; -GRANT USAGE ON SCHEMA metaschema_modules_public TO administrator, authenticated, anonymous; -GRANT USAGE ON SCHEMA services_public TO administrator, authenticated, anonymous; - --- Create object_category type if not exists -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_type t JOIN pg_namespace n ON t.typnamespace = n.oid WHERE t.typname = 'object_category' AND n.nspname = 'metaschema_public') THEN - CREATE TYPE metaschema_public.object_category AS ENUM ('core', 'module', 'app'); - END IF; -END -$$; - --- Create metaschema tables - --- database table -CREATE TABLE IF NOT EXISTS metaschema_public.database ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - owner_id uuid, - schema_hash text, - schema_name text, - private_schema_name text, - name text, - label text, - hash uuid, - UNIQUE(schema_hash), - UNIQUE(schema_name), - UNIQUE(private_schema_name) -); - --- schema table -CREATE TABLE IF NOT EXISTS metaschema_public.schema ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - name text NOT NULL, - schema_name text NOT NULL, - label text, - description text, - smart_tags jsonb, - category metaschema_public.object_category NOT NULL DEFAULT 'app', - module text NULL, - scope int NULL, - tags citext[] NOT NULL DEFAULT '{}', - is_public boolean NOT NULL DEFAULT TRUE, - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - UNIQUE (database_id, name), - UNIQUE (schema_name) -); - --- table table -CREATE TABLE IF NOT EXISTS metaschema_public.table ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - schema_id uuid NOT NULL, - name text NOT NULL, - label text, - description text, - smart_tags jsonb, - category metaschema_public.object_category NOT NULL DEFAULT 'app', - module text NULL, - scope int NULL, - use_rls boolean NOT NULL DEFAULT FALSE, - timestamps boolean NOT NULL DEFAULT FALSE, - peoplestamps boolean NOT NULL DEFAULT FALSE, - plural_name text, - singular_name text, - tags citext[] NOT NULL DEFAULT '{}', - inherits_id uuid NULL, - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE, - UNIQUE (database_id, name) -); - --- field table -CREATE TABLE IF NOT EXISTS metaschema_public.field ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - table_id uuid NOT NULL, - name text NOT NULL, - label text, - description text, - smart_tags jsonb, - is_required boolean NOT NULL DEFAULT FALSE, - default_value text NULL DEFAULT NULL, - default_value_ast jsonb NULL DEFAULT NULL, - is_hidden boolean NOT NULL DEFAULT FALSE, - type citext NOT NULL, - field_order int NOT NULL DEFAULT 0, - regexp text DEFAULT NULL, - chk jsonb DEFAULT NULL, - chk_expr jsonb DEFAULT NULL, - min float DEFAULT NULL, - max float DEFAULT NULL, - tags citext[] NOT NULL DEFAULT '{}', - category metaschema_public.object_category NOT NULL DEFAULT 'app', - module text NULL, - scope int NULL, - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT table_fkey FOREIGN KEY (table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE, - UNIQUE (table_id, name) -); - --- primary_key_constraint table -CREATE TABLE IF NOT EXISTS metaschema_public.primary_key_constraint ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - table_id uuid NOT NULL, - name text NOT NULL, - type char(1) NOT NULL DEFAULT 'p', - field_ids uuid[] NOT NULL, - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT table_fkey FOREIGN KEY (table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE -); - --- check_constraint table -CREATE TABLE IF NOT EXISTS metaschema_public.check_constraint ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - table_id uuid NOT NULL, - name text NOT NULL, - type char(1) NOT NULL DEFAULT 'c', - field_ids uuid[] NOT NULL, - expr jsonb, - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT table_fkey FOREIGN KEY (table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE -); - --- services_public tables - --- apis table -CREATE TABLE IF NOT EXISTS services_public.apis ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - name text NOT NULL, - dbname text NOT NULL DEFAULT current_database(), - role_name text NOT NULL DEFAULT 'authenticated', - anon_role text NOT NULL DEFAULT 'anonymous', - is_public boolean NOT NULL DEFAULT true, - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - UNIQUE(database_id, name) -); - -COMMENT ON CONSTRAINT db_fkey ON services_public.apis IS E'@omit manyToMany'; -CREATE INDEX IF NOT EXISTS apis_database_id_idx ON services_public.apis (database_id); - --- domains table -CREATE TABLE IF NOT EXISTS services_public.domains ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - api_id uuid, - site_id uuid, - subdomain hostname, - domain hostname, - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT api_fkey FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE, - UNIQUE (subdomain, domain) -); - -COMMENT ON CONSTRAINT db_fkey ON services_public.domains IS E'@omit manyToMany'; -CREATE INDEX IF NOT EXISTS domains_database_id_idx ON services_public.domains (database_id); -COMMENT ON CONSTRAINT api_fkey ON services_public.domains IS E'@omit manyToMany'; -CREATE INDEX IF NOT EXISTS domains_api_id_idx ON services_public.domains (api_id); - --- api_schemas table -CREATE TABLE IF NOT EXISTS services_public.api_schemas ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - schema_id uuid NOT NULL, - api_id uuid NOT NULL, - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE, - CONSTRAINT api_fkey FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE, - UNIQUE(api_id, schema_id) -); - --- api_extensions table (required by GraphQL ORM) -CREATE TABLE IF NOT EXISTS services_public.api_extensions ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid, - api_id uuid, - schema_name text, - CONSTRAINT db_fkey2 FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT api_fkey2 FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE -); - --- api_modules table (required by GraphQL ORM) -CREATE TABLE IF NOT EXISTS services_public.api_modules ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid, - api_id uuid, - name text, - data jsonb, - CONSTRAINT db_fkey3 FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT api_fkey3 FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE -); - --- rls_module table (required by GraphQL ORM) --- CONSTRAINT api_id_uniq UNIQUE(api_id) is critical - it creates the singular 'rlsModule' relation on Api type -CREATE TABLE IF NOT EXISTS metaschema_modules_public.rls_module ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - api_id uuid NOT NULL DEFAULT uuid_nil(), - schema_id uuid NOT NULL DEFAULT uuid_nil(), - private_schema_id uuid NOT NULL DEFAULT uuid_nil(), - tokens_table_id uuid NOT NULL DEFAULT uuid_nil(), - users_table_id uuid NOT NULL DEFAULT uuid_nil(), - authenticate text NOT NULL DEFAULT 'authenticate', - authenticate_strict text NOT NULL DEFAULT 'authenticate_strict', - "current_role" text NOT NULL DEFAULT 'current_user', - current_role_id text NOT NULL DEFAULT 'current_user_id', - CONSTRAINT db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT api_fkey FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE, - CONSTRAINT schema_fkey FOREIGN KEY (schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE, - CONSTRAINT pschema_fkey FOREIGN KEY (private_schema_id) REFERENCES metaschema_public.schema (id) ON DELETE CASCADE, - CONSTRAINT tokens_table_fkey FOREIGN KEY (tokens_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE, - CONSTRAINT users_table_fkey FOREIGN KEY (users_table_id) REFERENCES metaschema_public.table (id) ON DELETE CASCADE, - CONSTRAINT api_id_uniq UNIQUE(api_id) -); - --- Comments to control PostGraphile generation (match original schema) -COMMENT ON CONSTRAINT api_fkey ON metaschema_modules_public.rls_module IS E'@omit manyToMany'; -COMMENT ON CONSTRAINT schema_fkey ON metaschema_modules_public.rls_module IS E'@omit manyToMany'; -COMMENT ON CONSTRAINT pschema_fkey ON metaschema_modules_public.rls_module IS E'@omit manyToMany'; -COMMENT ON CONSTRAINT db_fkey ON metaschema_modules_public.rls_module IS E'@omit'; -COMMENT ON CONSTRAINT tokens_table_fkey ON metaschema_modules_public.rls_module IS E'@omit'; -COMMENT ON CONSTRAINT users_table_fkey ON metaschema_modules_public.rls_module IS E'@omit'; -CREATE INDEX rls_module_database_id_idx ON metaschema_modules_public.rls_module ( database_id ); - --- database_settings table (typed feature flags — database-wide defaults) -CREATE TABLE IF NOT EXISTS services_public.database_settings ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL UNIQUE, - enable_aggregates boolean NOT NULL DEFAULT false, - enable_postgis boolean NOT NULL DEFAULT true, - enable_search boolean NOT NULL DEFAULT true, - enable_direct_uploads boolean NOT NULL DEFAULT true, - enable_presigned_uploads boolean NOT NULL DEFAULT true, - enable_many_to_many boolean NOT NULL DEFAULT true, - enable_connection_filter boolean NOT NULL DEFAULT true, - enable_ltree boolean NOT NULL DEFAULT true, - enable_llm boolean NOT NULL DEFAULT false, - enable_realtime boolean NOT NULL DEFAULT false, - enable_bulk boolean NOT NULL DEFAULT false, - options jsonb NOT NULL DEFAULT '{}'::jsonb, - CONSTRAINT ds_db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE -); - --- api_settings table (per-API overrides — NULL = inherit from database_settings) -CREATE TABLE IF NOT EXISTS services_public.api_settings ( - id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), - database_id uuid NOT NULL, - api_id uuid NOT NULL UNIQUE, - enable_aggregates boolean, - enable_postgis boolean, - enable_search boolean, - enable_direct_uploads boolean, - enable_presigned_uploads boolean, - enable_many_to_many boolean, - enable_connection_filter boolean, - enable_ltree boolean, - enable_llm boolean, - enable_realtime boolean, - enable_bulk boolean, - options jsonb NOT NULL DEFAULT '{}'::jsonb, - CONSTRAINT as_db_fkey FOREIGN KEY (database_id) REFERENCES metaschema_public.database (id) ON DELETE CASCADE, - CONSTRAINT as_api_fkey FOREIGN KEY (api_id) REFERENCES services_public.apis (id) ON DELETE CASCADE -); - --- Grant permissions on metaschema tables -GRANT SELECT, INSERT, UPDATE, DELETE ON metaschema_public.database TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON metaschema_public.schema TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON metaschema_public.table TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON metaschema_public.field TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON metaschema_public.primary_key_constraint TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON metaschema_public.check_constraint TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON services_public.apis TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON services_public.domains TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON services_public.api_schemas TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON services_public.api_extensions TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON services_public.api_modules TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON services_public.database_settings TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON services_public.api_settings TO administrator, authenticated, anonymous; -GRANT SELECT, INSERT, UPDATE, DELETE ON metaschema_modules_public.rls_module TO administrator, authenticated, anonymous; diff --git a/graphql/server-test/__fixtures__/seed/simple-seed-services/test-data.sql b/graphql/server-test/__fixtures__/seed/simple-seed-services/test-data.sql deleted file mode 100644 index 02091c0a0..000000000 --- a/graphql/server-test/__fixtures__/seed/simple-seed-services/test-data.sql +++ /dev/null @@ -1,149 +0,0 @@ --- Test data for simple-seed-services scenario --- Inserts metaschema data, services data, and 5 animals - --- Use replica mode to bypass triggers/constraints during seed -SET session_replication_role TO replica; - --- ===================================================== --- METASCHEMA DATA --- ===================================================== - --- Database entry (ID matches servicesDatabaseId in test file) -INSERT INTO metaschema_public.database (id, owner_id, name, hash) -VALUES ( - '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', - NULL, - 'simple-pets', - '425a0f10-0170-5760-85df-2a980c378224' -) ON CONFLICT (id) DO NOTHING; - --- Schema entries -INSERT INTO metaschema_public.schema (id, database_id, name, schema_name, description, is_public) -VALUES - ('6dbae92a-5450-401b-1ed5-d69e7754940d', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'public', 'simple-pets-public', NULL, true), - ('6dba9876-043f-48ee-399d-ddc991ad978d', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'private', 'simple-pets-private', NULL, false), - ('6dba6f21-0193-43f4-3bdb-61b4b956b6b6', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'pets_public', 'simple-pets-pets-public', NULL, true) -ON CONFLICT (id) DO NOTHING; - --- Table entry for animals -INSERT INTO metaschema_public.table (id, database_id, schema_id, name, description) -VALUES ( - '6dba36e9-b098-4157-1b4c-e5b6e3a885de', - '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', - '6dba6f21-0193-43f4-3bdb-61b4b956b6b6', - 'animals', - NULL -) ON CONFLICT (id) DO NOTHING; - --- Field entries for animals table -INSERT INTO metaschema_public.field (id, database_id, table_id, name, type, description) -VALUES - ('6dbace4d-bcf9-4d55-e363-6b24623f0d8a', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dba36e9-b098-4157-1b4c-e5b6e3a885de', 'id', 'uuid', NULL), - ('6dbae9c7-3460-4f65-8290-b2a8e05eb714', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dba36e9-b098-4157-1b4c-e5b6e3a885de', 'name', 'text', NULL), - ('6dbacc68-876e-4ece-b190-706819ae4f00', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dba36e9-b098-4157-1b4c-e5b6e3a885de', 'species', 'text', NULL), - ('6dba080e-bb3f-4556-8ca7-425ceb98a519', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dba36e9-b098-4157-1b4c-e5b6e3a885de', 'owner_id', 'uuid', NULL) -ON CONFLICT (id) DO NOTHING; - --- Primary key constraint -INSERT INTO metaschema_public.primary_key_constraint (id, database_id, table_id, name, type, field_ids) -VALUES ( - '6dbaeb74-b5cf-46d5-4724-6ab26c27da2d', - '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', - '6dba36e9-b098-4157-1b4c-e5b6e3a885de', - 'animals_pkey', - 'p', - '{6dbace4d-bcf9-4d55-e363-6b24623f0d8a}' -) ON CONFLICT (id) DO NOTHING; - --- Check constraints -INSERT INTO metaschema_public.check_constraint (id, database_id, table_id, name, type, field_ids, expr) -VALUES - ( - '6dbade3d-1f49-4535-148f-a55415f91990', - '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', - '6dba36e9-b098-4157-1b4c-e5b6e3a885de', - 'animals_name_chk', - 'c', - '{6dbae9c7-3460-4f65-8290-b2a8e05eb714}', - '{"A_Expr":{"kind":"AEXPR_OP","name":[{"String":{"sval":"<="}}],"lexpr":{"FuncCall":{"args":[{"ColumnRef":{"fields":[{"String":{"sval":"name"}}]}}],"funcname":[{"String":{"sval":"character_length"}}]}},"rexpr":{"A_Const":{"ival":256}}}}' - ), - ( - '6dba5892-fa63-4c33-b067-43d07fc93032', - '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', - '6dba36e9-b098-4157-1b4c-e5b6e3a885de', - 'animals_species_chk', - 'c', - '{6dbacc68-876e-4ece-b190-706819ae4f00}', - '{"A_Expr":{"kind":"AEXPR_OP","name":[{"String":{"sval":"<="}}],"lexpr":{"FuncCall":{"args":[{"ColumnRef":{"fields":[{"String":{"sval":"species"}}]}}],"funcname":[{"String":{"sval":"character_length"}}]}},"rexpr":{"A_Const":{"ival":100}}}}' - ) -ON CONFLICT (id) DO NOTHING; - --- ===================================================== --- SERVICES DATA --- ===================================================== - --- API entries --- "app" API - public, used for domain lookup via Host header (app.test.constructive.io) --- "private" API - private, used for X-Api-Name lookup --- Additional APIs for coverage -INSERT INTO services_public.apis (id, database_id, name, dbname, is_public, role_name, anon_role) -VALUES - ('6c9997a4-591b-4cb3-9313-4ef45d6f134e', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'app', current_database(), true, 'authenticated', 'anonymous'), - ('e257c53d-6ba6-40de-b679-61b37188a316', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'private', current_database(), false, 'administrator', 'administrator'), - ('28199444-da40-40b1-8a4c-53edbf91c738', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'public', current_database(), true, 'authenticated', 'anonymous'), - ('cc1e8389-e69d-4e12-9089-a98bf11fc75f', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'admin', current_database(), true, 'authenticated', 'anonymous'), - ('a2e6098f-2c11-4f2a-b481-c19175bc62ef', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', 'auth', current_database(), true, 'authenticated', 'anonymous') -ON CONFLICT (id) DO NOTHING; - --- Domain entry - maps app.test.constructive.io to the "app" API --- Note: URL parser sees "app.test.constructive.io" as domain=constructive.io, subdomain=app.test -INSERT INTO services_public.domains (id, database_id, site_id, api_id, domain, subdomain) -VALUES ( - '41181146-890e-4991-9da7-3dddf87d9e78', - '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', - NULL, - '6c9997a4-591b-4cb3-9313-4ef45d6f134e', - 'constructive.io', - 'app.test' -) ON CONFLICT (id) DO NOTHING; - --- Domain entry for private API fallback test (Q3 Sub-D) --- Note: URL parser sees "private.test.constructive.io" as domain=constructive.io, subdomain=private.test -INSERT INTO services_public.domains (id, database_id, site_id, api_id, domain, subdomain) -VALUES ( - '51181146-890e-4991-9da7-3dddf87d9e79', - '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', - NULL, - 'e257c53d-6ba6-40de-b679-61b37188a316', - 'constructive.io', - 'private.test' -) ON CONFLICT (id) DO NOTHING; - --- API Schemas - link APIs to schemas -INSERT INTO services_public.api_schemas (id, database_id, schema_id, api_id) -VALUES - -- app API schemas - ('71181146-890e-4991-9da7-3dddf87d9e01', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dbae92a-5450-401b-1ed5-d69e7754940d', '6c9997a4-591b-4cb3-9313-4ef45d6f134e'), - ('71181146-890e-4991-9da7-3dddf87d9e02', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dba6f21-0193-43f4-3bdb-61b4b956b6b6', '6c9997a4-591b-4cb3-9313-4ef45d6f134e'), - -- private API schemas - ('71181146-890e-4991-9da7-3dddf87d9e03', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dbae92a-5450-401b-1ed5-d69e7754940d', 'e257c53d-6ba6-40de-b679-61b37188a316'), - ('71181146-890e-4991-9da7-3dddf87d9e04', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dba9876-043f-48ee-399d-ddc991ad978d', 'e257c53d-6ba6-40de-b679-61b37188a316'), - ('71181146-890e-4991-9da7-3dddf87d9e05', '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9', '6dba6f21-0193-43f4-3bdb-61b4b956b6b6', 'e257c53d-6ba6-40de-b679-61b37188a316') -ON CONFLICT (id) DO NOTHING; - --- ===================================================== --- TEST DATA (ANIMALS) --- ===================================================== - --- Insert 5 animals: 2 Dogs, 2 Cats, 1 Bird -INSERT INTO "simple-pets-pets-public".animals (id, name, species, owner_id, created_at, updated_at) -VALUES - ('a0000001-0000-0000-0000-000000000001', 'Buddy', 'Dog', NULL, now(), now()), - ('a0000001-0000-0000-0000-000000000002', 'Max', 'Dog', NULL, now(), now()), - ('a0000001-0000-0000-0000-000000000003', 'Whiskers', 'Cat', NULL, now(), now()), - ('a0000001-0000-0000-0000-000000000004', 'Mittens', 'Cat', NULL, now(), now()), - ('a0000001-0000-0000-0000-000000000005', 'Tweety', 'Bird', NULL, now(), now()) -ON CONFLICT (id) DO NOTHING; - --- Reset replication role -SET session_replication_role TO DEFAULT; diff --git a/graphql/server-test/__tests__/express-context.integration.test.ts b/graphql/server-test/__tests__/express-context.integration.test.ts index 091dde789..520746b3d 100644 --- a/graphql/server-test/__tests__/express-context.integration.test.ts +++ b/graphql/server-test/__tests__/express-context.integration.test.ts @@ -7,8 +7,8 @@ * * parseDomains → requestId → API resolver → auth → createContextMiddleware * - * Uses the shared seed fixtures from __fixtures__/seed/ (root-level) - * and the local simple-seed-services fixtures for the full services stack. + * Uses the shared seed fixtures from __fixtures__/seed/ (repo root-level) + * for the full metaschema + services + app-schemas stack. * * Run tests: * pnpm test -- --testPathPattern=express-context.integration @@ -21,9 +21,9 @@ import type supertest from 'supertest'; jest.setTimeout(30000); -const seedRoot = path.join(__dirname, '..', '__fixtures__', 'seed'); -const sql = (seedDir: string, file: string) => - path.join(seedRoot, seedDir, file); +const sharedSeedRoot = path.join(__dirname, '..', '..', '..', '__fixtures__', 'seed'); +const shared = (...segments: string[]) => + path.join(sharedSeedRoot, ...segments); const schemas = ['simple-pets-public', 'simple-pets-pets-public']; const metaSchemas = [ 'services_public', @@ -32,9 +32,10 @@ const metaSchemas = [ ]; const seedFiles = [ - sql('simple-seed-services', 'setup.sql'), - sql('simple-seed-services', 'schema.sql'), - sql('simple-seed-services', 'test-data.sql'), + shared('services', 'setup.sql'), + shared('app-schemas', 'simple-pets', 'schema.sql'), + shared('services', 'test-data.sql'), + shared('app-schemas', 'simple-pets', 'test-data.sql'), ]; let server: ServerInfo; diff --git a/graphql/server-test/__tests__/server.integration.test.ts b/graphql/server-test/__tests__/server.integration.test.ts index 2f39717aa..f8fef844b 100644 --- a/graphql/server-test/__tests__/server.integration.test.ts +++ b/graphql/server-test/__tests__/server.integration.test.ts @@ -12,9 +12,12 @@ import type supertest from 'supertest'; jest.setTimeout(30000); -const seedRoot = path.join(__dirname, '..', '__fixtures__', 'seed'); +const localSeedRoot = path.join(__dirname, '..', '__fixtures__', 'seed'); +const sharedSeedRoot = path.join(__dirname, '..', '..', '..', '__fixtures__', 'seed'); const sql = (seedDir: string, file: string) => - path.join(seedRoot, seedDir, file); + path.join(localSeedRoot, seedDir, file); +const shared = (...segments: string[]) => + path.join(sharedSeedRoot, ...segments); const schemas = ['simple-pets-public', 'simple-pets-pets-public']; const servicesDatabaseId = '80a2eaaf-f77e-4bfe-8506-df929ef1b8d9'; const metaSchemas = [ @@ -98,11 +101,21 @@ const scenarios: Scenario[] = [ }, ]; -const seedFilesFor = (seedDir: Scenario['seedDir']) => [ - sql(seedDir, 'setup.sql'), - sql(seedDir, 'schema.sql'), - sql(seedDir, 'test-data.sql'), -]; +const seedFilesFor = (seedDir: Scenario['seedDir']) => { + if (seedDir === 'simple-seed-services') { + return [ + shared('services', 'setup.sql'), + shared('app-schemas', 'simple-pets', 'schema.sql'), + shared('services', 'test-data.sql'), + shared('app-schemas', 'simple-pets', 'test-data.sql'), + ]; + } + return [ + sql(seedDir, 'setup.sql'), + sql(seedDir, 'schema.sql'), + sql(seedDir, 'test-data.sql'), + ]; +}; const buildSeedAdapters = (scenario: Scenario) => [ seed.sqlfile(seedFilesFor(scenario.seedDir)), diff --git a/graphql/server-test/__tests__/upload.integration.test.ts b/graphql/server-test/__tests__/upload.integration.test.ts index 5f4eeb9e5..10c8b0623 100644 --- a/graphql/server-test/__tests__/upload.integration.test.ts +++ b/graphql/server-test/__tests__/upload.integration.test.ts @@ -35,9 +35,12 @@ import type supertest from 'supertest'; jest.setTimeout(120000); -const seedRoot = path.join(__dirname, '..', '__fixtures__', 'seed'); +const localSeedRoot = path.join(__dirname, '..', '__fixtures__', 'seed'); +const sharedSeedRoot = path.join(__dirname, '..', '..', '..', '__fixtures__', 'seed'); const sql = (seedDir: string, file: string) => - path.join(seedRoot, seedDir, file); + path.join(localSeedRoot, seedDir, file); +const shared = (...segments: string[]) => + path.join(sharedSeedRoot, ...segments); // ========================================================================= // Tenant constants @@ -67,7 +70,7 @@ const metaSchemas = [ ]; const seedFiles = [ - sql('simple-seed-services', 'setup.sql'), + shared('services', 'setup.sql'), sql('simple-seed-storage', 'setup.sql'), sql('simple-seed-storage', 'schema.sql'), sql('simple-seed-storage', 'test-data.sql'),