diff --git a/pgpm/export/__tests__/cross-flow-parity.test.ts b/pgpm/export/__tests__/cross-flow-parity.test.ts index 7a0a4f6c6..3afd236d4 100644 --- a/pgpm/export/__tests__/cross-flow-parity.test.ts +++ b/pgpm/export/__tests__/cross-flow-parity.test.ts @@ -44,7 +44,7 @@ const SITE_ID = 'c1000001-0000-0000-0000-000000000001'; const DOMAIN_ID = 'c2000001-0000-0000-0000-000000000001'; const API_SCHEMA_ID = 'c3000001-0000-0000-0000-000000000001'; const INDEX_ID = 'd0000001-0000-0000-0000-000000000001'; -const RLS_FUNCTION_ID = 'd1000001-0000-0000-0000-000000000001'; +const POLICY_ID = 'd1000001-0000-0000-0000-000000000001'; const CORS_SETTINGS_ID = 'd2000001-0000-0000-0000-000000000001'; const USER_AUTH_MODULE_ID = 'd3000001-0000-0000-0000-000000000001'; @@ -390,7 +390,7 @@ describe('Cross-flow parity: exportMeta vs exportGraphQLMeta', () => { predicates jsonb, is_unique boolean ); - CREATE TABLE metaschema_public.rls_function ( + CREATE TABLE metaschema_public.policy ( id uuid PRIMARY KEY, database_id uuid, schema_id uuid, @@ -478,11 +478,11 @@ describe('Cross-flow parity: exportMeta vs exportGraphQLMeta', () => { VALUES ($1, $2, $3, $4, 'users_pkey', 'btree', ARRAY[$5]::uuid[], '{"columns": ["id"]}'::jsonb, true) `, [INDEX_ID, DATABASE_ID, SCHEMA_ID_PUB, TABLE_ID_USERS, FIELD_ID_1]); - // rls_function table — tests boolean and int columns + // policy table — tests boolean and int columns await pg.query(` - INSERT INTO metaschema_public.rls_function (id, database_id, schema_id, table_id, role_name, command, function_name, is_using, force_enabled, priority) + INSERT INTO metaschema_public.policy (id, database_id, schema_id, table_id, role_name, command, function_name, is_using, force_enabled, priority) VALUES ($1, $2, $3, $4, 'authenticated', 'SELECT', 'check_owner', true, true, 10) - `, [RLS_FUNCTION_ID, DATABASE_ID, SCHEMA_ID_PUB, TABLE_ID_USERS]); + `, [POLICY_ID, DATABASE_ID, SCHEMA_ID_PUB, TABLE_ID_USERS]); // cors_settings table — tests text[] columns await pg.query(` @@ -660,7 +660,7 @@ describe('Cross-flow parity: exportMeta vs exportGraphQLMeta', () => { expect(gqlResult['index']?.trim()).toBe(sqlResult['index']?.trim()); }); - it('rls_function table with boolean and int columns should be identical across both flows', async () => { + it('policy table with boolean and int columns should be identical across both flows', async () => { const sqlResult = await exportMeta({ opts: { pg: dbConfig }, dbname: dbConfig.database, @@ -673,9 +673,9 @@ describe('Cross-flow parity: exportMeta vs exportGraphQLMeta', () => { database_id: DATABASE_ID }); - expect(sqlResult['rls_function']).toBeDefined(); - expect(gqlResult['rls_function']).toBeDefined(); - expect(gqlResult['rls_function']?.trim()).toBe(sqlResult['rls_function']?.trim()); + expect(sqlResult['policy']).toBeDefined(); + expect(gqlResult['policy']).toBeDefined(); + expect(gqlResult['policy']?.trim()).toBe(sqlResult['policy']?.trim()); }); it('cors_settings table with text[] columns should be identical across both flows', async () => { diff --git a/pgpm/export/__tests__/export-meta.test.ts b/pgpm/export/__tests__/export-meta.test.ts index 15012a6e0..b72bd63b1 100644 --- a/pgpm/export/__tests__/export-meta.test.ts +++ b/pgpm/export/__tests__/export-meta.test.ts @@ -14,7 +14,7 @@ describe('Export Meta Config Validation', () => { describe('metaschema_public tables', () => { const required = [ 'database', 'schema', 'table', 'field', - 'policy', 'index', 'trigger', 'trigger_function', 'rls_function', + 'policy', 'index', 'trigger', 'trigger_function', 'foreign_key_constraint', 'primary_key_constraint', 'unique_constraint', 'check_constraint', 'full_text_search', 'schema_grant', 'table_grant', 'default_privilege' @@ -32,7 +32,7 @@ describe('Export Meta Config Validation', () => { const required = [ 'domains', 'sites', 'apis', 'apps', 'site_modules', 'site_themes', 'site_metadata', - 'api_modules', 'api_extensions', 'api_schemas' + 'api_modules', 'api_schemas' ]; it('should include all required services_public tables in config', () => { @@ -46,7 +46,7 @@ describe('Export Meta Config Validation', () => { describe('metaschema_modules_public tables', () => { const required = [ 'rls_module', 'user_auth_module', 'memberships_module', - 'permissions_module', 'limits_module', 'levels_module', + 'permissions_module', 'limits_module', 'events_module', 'users_module', 'hierarchy_module', 'membership_types_module', 'invites_module', 'emails_module', 'sessions_module', @@ -54,8 +54,7 @@ describe('Export Meta Config Validation', () => { 'user_credentials_module', 'user_settings_module', 'connected_accounts_module', 'phone_numbers_module', 'crypto_addresses_module', 'crypto_auth_module', - 'field_module', 'table_module', - 'secure_table_provision', 'uuid_module', 'default_ids_module', + 'secure_table_provision', 'default_ids_module', 'denormalized_table_field', 'relation_provision', 'entity_type_provision', 'rate_limits_module', 'storage_module', diff --git a/pgpm/export/__tests__/export-utils.test.ts b/pgpm/export/__tests__/export-utils.test.ts index 7cda2784f..6bc7a62be 100644 --- a/pgpm/export/__tests__/export-utils.test.ts +++ b/pgpm/export/__tests__/export-utils.test.ts @@ -13,6 +13,7 @@ import path from 'path'; import { META_TABLE_CONFIG, META_TABLE_ORDER, + META_TABLE_OVERRIDES, DB_REQUIRED_EXTENSIONS, SERVICE_REQUIRED_EXTENSIONS, META_COMMON_HEADER, @@ -100,56 +101,28 @@ describe('META_TABLE_CONFIG and META_TABLE_ORDER consistency', () => { // ============================================================================= describe('SQL and GraphQL flow table parity', () => { - let sqlFlowTables: string[]; - let graphqlFlowTables: string[]; + let sqlSource: string; + let gqlSource: string; beforeAll(() => { - // Extract queryAndParse keys from export-meta.ts - const sqlSource = readFileSync( - join(__dirname, '../src/export-meta.ts'), - 'utf-8' - ); - sqlFlowTables = [...sqlSource.matchAll(/queryAndParse\('(\w+)'/g)].map(m => m[1]); - - // Extract queryAndParse keys from export-graphql-meta.ts - const gqlSource = readFileSync( - join(__dirname, '../src/export-graphql-meta.ts'), - 'utf-8' - ); - graphqlFlowTables = [...gqlSource.matchAll(/queryAndParse\('(\w+)'/g)].map(m => m[1]); + sqlSource = readFileSync(join(__dirname, '../src/export-meta.ts'), 'utf-8'); + gqlSource = readFileSync(join(__dirname, '../src/export-graphql-meta.ts'), 'utf-8'); }); - it('both flows should query the same set of tables', () => { - const sqlSet = new Set(sqlFlowTables); - const gqlSet = new Set(graphqlFlowTables); - - const inSqlNotGql = sqlFlowTables.filter(t => !gqlSet.has(t)); - const inGqlNotSql = graphqlFlowTables.filter(t => !sqlSet.has(t)); - - expect(inSqlNotGql).toEqual([]); - expect(inGqlNotSql).toEqual([]); + it('both flows should iterate the generated manifest via META_TABLE_ORDER', () => { + expect(sqlSource).toContain('META_TABLE_ORDER'); + expect(gqlSource).toContain('META_TABLE_ORDER'); }); - it('all queried tables should have entries in META_TABLE_CONFIG', () => { - const configKeys = new Set(Object.keys(META_TABLE_CONFIG)); - - const sqlMissing = sqlFlowTables.filter(t => !configKeys.has(t)); - const gqlMissing = graphqlFlowTables.filter(t => !configKeys.has(t)); - - expect(sqlMissing).toEqual([]); - expect(gqlMissing).toEqual([]); + it('neither flow should have hardcoded per-table queryAndParse calls', () => { + expect([...sqlSource.matchAll(/queryAndParse\('(\w+)'/g)]).toEqual([]); + expect([...gqlSource.matchAll(/queryAndParse\('(\w+)'/g)]).toEqual([]); }); - it('every key in META_TABLE_CONFIG should be queried by both flows', () => { - const sqlSet = new Set(sqlFlowTables); - const gqlSet = new Set(graphqlFlowTables); - const configKeys = Object.keys(META_TABLE_CONFIG); - - const notQueriedBySql = configKeys.filter(k => !sqlSet.has(k)); - const notQueriedByGql = configKeys.filter(k => !gqlSet.has(k)); - - expect(notQueriedBySql).toEqual([]); - expect(notQueriedByGql).toEqual([]); + it('every override key should exist in the generated manifest config', () => { + const configKeys = new Set(Object.keys(META_TABLE_CONFIG)); + const orphaned = Object.keys(META_TABLE_OVERRIDES).filter(k => !configKeys.has(k)); + expect(orphaned).toEqual([]); }); }); diff --git a/pgpm/export/src/export-graphql-meta.ts b/pgpm/export/src/export-graphql-meta.ts index 5740f0699..c55bf0b96 100644 --- a/pgpm/export/src/export-graphql-meta.ts +++ b/pgpm/export/src/export-graphql-meta.ts @@ -8,7 +8,7 @@ import { Parser } from 'csv-to-pg'; import { toSnakeCase } from 'inflekt'; -import { FieldType, META_TABLE_CONFIG, TableConfig } from './export-utils'; +import { FieldType, META_TABLE_CONFIG, META_TABLE_ORDER, TableConfig } from './export-utils'; import { GraphQLClient } from './graphql-client'; import { buildFieldsFragment, @@ -244,114 +244,17 @@ export const exportGraphQLMeta = async ({ // Batch queries by schema group — independent HTTP requests run in parallel // within each group for significant speedup over sequential awaits. - - // metaschema_public tables - await Promise.all([ - queryAndParse('database'), - queryAndParse('schema'), - queryAndParse('function'), - queryAndParse('spatial_relation'), - queryAndParse('table'), - queryAndParse('field'), - queryAndParse('policy'), - queryAndParse('index'), - queryAndParse('trigger'), - queryAndParse('trigger_function'), - queryAndParse('rls_function'), - queryAndParse('foreign_key_constraint'), - queryAndParse('primary_key_constraint'), - queryAndParse('unique_constraint'), - queryAndParse('check_constraint'), - queryAndParse('full_text_search'), - queryAndParse('schema_grant'), - queryAndParse('table_grant'), - queryAndParse('default_privilege') - ]); - - // services_public tables - await Promise.all([ - queryAndParse('domains'), - queryAndParse('sites'), - queryAndParse('apis'), - queryAndParse('apps'), - queryAndParse('site_modules'), - queryAndParse('site_themes'), - queryAndParse('site_metadata'), - queryAndParse('api_modules'), - queryAndParse('api_extensions'), - queryAndParse('api_schemas'), - queryAndParse('database_settings'), - queryAndParse('api_settings'), - queryAndParse('rls_settings'), - queryAndParse('cors_settings'), - queryAndParse('pubkey_settings'), - queryAndParse('webauthn_settings') - ]); - - // metaschema_modules_public tables - await Promise.all([ - queryAndParse('rls_module'), - queryAndParse('user_auth_module'), - queryAndParse('memberships_module'), - queryAndParse('permissions_module'), - queryAndParse('limits_module'), - queryAndParse('levels_module'), - queryAndParse('events_module'), - queryAndParse('users_module'), - queryAndParse('hierarchy_module'), - queryAndParse('membership_types_module'), - queryAndParse('invites_module'), - queryAndParse('emails_module'), - queryAndParse('sessions_module'), - queryAndParse('user_state_module'), - queryAndParse('profiles_module'), - queryAndParse('config_secrets_user_module'), - queryAndParse('user_credentials_module'), - queryAndParse('user_settings_module'), - queryAndParse('connected_accounts_module'), - queryAndParse('phone_numbers_module'), - queryAndParse('crypto_addresses_module'), - queryAndParse('crypto_auth_module'), - queryAndParse('field_module'), - queryAndParse('table_module'), - queryAndParse('secure_table_provision'), - queryAndParse('uuid_module'), - queryAndParse('default_ids_module'), - queryAndParse('denormalized_table_field'), - queryAndParse('relation_provision'), - queryAndParse('entity_type_provision'), - queryAndParse('rate_limits_module'), - queryAndParse('storage_module'), - queryAndParse('billing_module'), - queryAndParse('billing_provider_module'), - queryAndParse('devices_module'), - queryAndParse('identity_providers_module'), - queryAndParse('integration_providers_module'), - queryAndParse('notifications_module'), - queryAndParse('plans_module'), - queryAndParse('realtime_module'), - queryAndParse('session_secrets_module'), - queryAndParse('infra_secrets_module'), - queryAndParse('infra_config_module'), - queryAndParse('internal_secrets_module'), - queryAndParse('i18n_module'), - queryAndParse('agent_module'), - queryAndParse('function_module'), - queryAndParse('namespace_module'), - queryAndParse('merkle_store_module'), - queryAndParse('graph_module'), - queryAndParse('graph_execution_module'), - queryAndParse('function_deployment_module'), - queryAndParse('function_invocation_module'), - queryAndParse('compute_log_module'), - queryAndParse('db_usage_module'), - queryAndParse('storage_log_module'), - queryAndParse('transfer_log_module'), - queryAndParse('webauthn_auth_module'), - queryAndParse('webauthn_credentials_module'), - queryAndParse('inference_log_module'), - queryAndParse('rate_limit_meters_module') - ]); + // Tables come from the generated manifest (see export-utils.ts); groups run + // sequentially in manifest schema order. + const keysBySchema = new Map(); + for (const key of META_TABLE_ORDER) { + const schema = META_TABLE_CONFIG[key].schema; + if (!keysBySchema.has(schema)) keysBySchema.set(schema, []); + keysBySchema.get(schema).push(key); + } + for (const keys of keysBySchema.values()) { + await Promise.all(keys.map(key => queryAndParse(key))); + } return sql; }; diff --git a/pgpm/export/src/export-meta.ts b/pgpm/export/src/export-meta.ts index 4f263688d..fac7a7bb0 100644 --- a/pgpm/export/src/export-meta.ts +++ b/pgpm/export/src/export-meta.ts @@ -3,7 +3,7 @@ import { Parser } from 'csv-to-pg'; import { getPgPool } from 'pg-cache'; import type { Pool } from 'pg'; -import { FieldType, TableConfig, META_TABLE_CONFIG, mapPgTypeToFieldType } from './export-utils'; +import { FieldType, TableConfig, META_TABLE_CONFIG, META_TABLE_ORDER, mapPgTypeToFieldType } from './export-utils'; /** * Query actual columns from information_schema for a given table. @@ -173,113 +173,14 @@ export const exportMeta = async ({ opts, dbname, database_id }: ExportMetaParams } }; - // ============================================================================= - // metaschema_public tables - // ============================================================================= - await queryAndParse('database', `SELECT * FROM metaschema_public.database WHERE id = $1 ORDER BY id`); - await queryAndParse('schema', `SELECT * FROM metaschema_public.schema WHERE database_id = $1 ORDER BY id`); - await queryAndParse('function', `SELECT * FROM metaschema_public.function WHERE database_id = $1 ORDER BY id`); - await queryAndParse('spatial_relation', `SELECT * FROM metaschema_public.spatial_relation WHERE database_id = $1 ORDER BY id`); - await queryAndParse('table', `SELECT * FROM metaschema_public.table WHERE database_id = $1 ORDER BY id`); - await queryAndParse('field', `SELECT * FROM metaschema_public.field WHERE database_id = $1 ORDER BY id`); - await queryAndParse('policy', `SELECT * FROM metaschema_public.policy WHERE database_id = $1 ORDER BY id`); - await queryAndParse('index', `SELECT * FROM metaschema_public.index WHERE database_id = $1 ORDER BY id`); - await queryAndParse('trigger', `SELECT * FROM metaschema_public.trigger WHERE database_id = $1 ORDER BY id`); - await queryAndParse('trigger_function', `SELECT * FROM metaschema_public.trigger_function WHERE database_id = $1 ORDER BY id`); - await queryAndParse('rls_function', `SELECT * FROM metaschema_public.rls_function WHERE database_id = $1 ORDER BY id`); - await queryAndParse('foreign_key_constraint', `SELECT * FROM metaschema_public.foreign_key_constraint WHERE database_id = $1 ORDER BY id`); - await queryAndParse('primary_key_constraint', `SELECT * FROM metaschema_public.primary_key_constraint WHERE database_id = $1 ORDER BY id`); - await queryAndParse('unique_constraint', `SELECT * FROM metaschema_public.unique_constraint WHERE database_id = $1 ORDER BY id`); - await queryAndParse('check_constraint', `SELECT * FROM metaschema_public.check_constraint WHERE database_id = $1 ORDER BY id`); - await queryAndParse('full_text_search', `SELECT * FROM metaschema_public.full_text_search WHERE database_id = $1 ORDER BY id`); - await queryAndParse('schema_grant', `SELECT * FROM metaschema_public.schema_grant WHERE database_id = $1 ORDER BY id`); - await queryAndParse('table_grant', `SELECT * FROM metaschema_public.table_grant WHERE database_id = $1 ORDER BY id`); - await queryAndParse('default_privilege', `SELECT * FROM metaschema_public.default_privilege WHERE database_id = $1 ORDER BY id`); - - // ============================================================================= - // services_public tables - // ============================================================================= - await queryAndParse('domains', `SELECT * FROM services_public.domains WHERE database_id = $1 ORDER BY id`); - await queryAndParse('sites', `SELECT * FROM services_public.sites WHERE database_id = $1 ORDER BY id`); - await queryAndParse('apis', `SELECT * FROM services_public.apis WHERE database_id = $1 ORDER BY id`); - await queryAndParse('apps', `SELECT * FROM services_public.apps WHERE database_id = $1 ORDER BY id`); - await queryAndParse('site_modules', `SELECT * FROM services_public.site_modules WHERE database_id = $1 ORDER BY id`); - await queryAndParse('site_themes', `SELECT * FROM services_public.site_themes WHERE database_id = $1 ORDER BY id`); - await queryAndParse('site_metadata', `SELECT * FROM services_public.site_metadata WHERE database_id = $1 ORDER BY id`); - await queryAndParse('api_modules', `SELECT * FROM services_public.api_modules WHERE database_id = $1 ORDER BY id`); - await queryAndParse('api_extensions', `SELECT * FROM services_public.api_extensions WHERE database_id = $1 ORDER BY id`); - await queryAndParse('api_schemas', `SELECT * FROM services_public.api_schemas WHERE database_id = $1 ORDER BY id`); - await queryAndParse('database_settings', `SELECT * FROM services_public.database_settings WHERE database_id = $1 ORDER BY id`); - await queryAndParse('api_settings', `SELECT * FROM services_public.api_settings WHERE database_id = $1 ORDER BY id`); - await queryAndParse('rls_settings', `SELECT * FROM services_public.rls_settings WHERE database_id = $1 ORDER BY id`); - await queryAndParse('cors_settings', `SELECT * FROM services_public.cors_settings WHERE database_id = $1 ORDER BY id`); - await queryAndParse('pubkey_settings', `SELECT * FROM services_public.pubkey_settings WHERE database_id = $1 ORDER BY id`); - await queryAndParse('webauthn_settings', `SELECT * FROM services_public.webauthn_settings WHERE database_id = $1 ORDER BY id`); - - // ============================================================================= - // metaschema_modules_public tables - // ============================================================================= - await queryAndParse('rls_module', `SELECT * FROM metaschema_modules_public.rls_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('user_auth_module', `SELECT * FROM metaschema_modules_public.user_auth_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('memberships_module', `SELECT * FROM metaschema_modules_public.memberships_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('permissions_module', `SELECT * FROM metaschema_modules_public.permissions_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('limits_module', `SELECT * FROM metaschema_modules_public.limits_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('levels_module', `SELECT * FROM metaschema_modules_public.levels_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('events_module', `SELECT * FROM metaschema_modules_public.events_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('users_module', `SELECT * FROM metaschema_modules_public.users_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('hierarchy_module', `SELECT * FROM metaschema_modules_public.hierarchy_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('membership_types_module', `SELECT * FROM metaschema_modules_public.membership_types_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('invites_module', `SELECT * FROM metaschema_modules_public.invites_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('emails_module', `SELECT * FROM metaschema_modules_public.emails_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('sessions_module', `SELECT * FROM metaschema_modules_public.sessions_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('user_state_module', `SELECT * FROM metaschema_modules_public.user_state_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('profiles_module', `SELECT * FROM metaschema_modules_public.profiles_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('config_secrets_user_module', `SELECT * FROM metaschema_modules_public.config_secrets_user_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('user_credentials_module', `SELECT * FROM metaschema_modules_public.user_credentials_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('user_settings_module', `SELECT * FROM metaschema_modules_public.user_settings_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('connected_accounts_module', `SELECT * FROM metaschema_modules_public.connected_accounts_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('phone_numbers_module', `SELECT * FROM metaschema_modules_public.phone_numbers_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('crypto_addresses_module', `SELECT * FROM metaschema_modules_public.crypto_addresses_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('crypto_auth_module', `SELECT * FROM metaschema_modules_public.crypto_auth_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('field_module', `SELECT * FROM metaschema_modules_public.field_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('table_module', `SELECT * FROM metaschema_modules_public.table_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('secure_table_provision', `SELECT * FROM metaschema_modules_public.secure_table_provision WHERE database_id = $1 ORDER BY id`); - await queryAndParse('uuid_module', `SELECT * FROM metaschema_modules_public.uuid_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('default_ids_module', `SELECT * FROM metaschema_modules_public.default_ids_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('denormalized_table_field', `SELECT * FROM metaschema_modules_public.denormalized_table_field WHERE database_id = $1 ORDER BY id`); - await queryAndParse('relation_provision', `SELECT * FROM metaschema_modules_public.relation_provision WHERE database_id = $1 ORDER BY id`); - await queryAndParse('entity_type_provision', `SELECT * FROM metaschema_modules_public.entity_type_provision WHERE database_id = $1 ORDER BY id`); - await queryAndParse('rate_limits_module', `SELECT * FROM metaschema_modules_public.rate_limits_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('storage_module', `SELECT * FROM metaschema_modules_public.storage_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('billing_module', `SELECT * FROM metaschema_modules_public.billing_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('billing_provider_module', `SELECT * FROM metaschema_modules_public.billing_provider_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('devices_module', `SELECT * FROM metaschema_modules_public.devices_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('identity_providers_module', `SELECT * FROM metaschema_modules_public.identity_providers_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('integration_providers_module', `SELECT * FROM metaschema_modules_public.integration_providers_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('notifications_module', `SELECT * FROM metaschema_modules_public.notifications_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('plans_module', `SELECT * FROM metaschema_modules_public.plans_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('realtime_module', `SELECT * FROM metaschema_modules_public.realtime_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('session_secrets_module', `SELECT * FROM metaschema_modules_public.session_secrets_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('infra_secrets_module', `SELECT * FROM metaschema_modules_public.infra_secrets_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('infra_config_module', `SELECT * FROM metaschema_modules_public.infra_config_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('internal_secrets_module', `SELECT * FROM metaschema_modules_public.internal_secrets_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('i18n_module', `SELECT * FROM metaschema_modules_public.i18n_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('agent_module', `SELECT * FROM metaschema_modules_public.agent_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('function_module', `SELECT * FROM metaschema_modules_public.function_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('namespace_module', `SELECT * FROM metaschema_modules_public.namespace_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('merkle_store_module', `SELECT * FROM metaschema_modules_public.merkle_store_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('graph_module', `SELECT * FROM metaschema_modules_public.graph_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('graph_execution_module', `SELECT * FROM metaschema_modules_public.graph_execution_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('function_deployment_module', `SELECT * FROM metaschema_modules_public.function_deployment_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('function_invocation_module', `SELECT * FROM metaschema_modules_public.function_invocation_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('compute_log_module', `SELECT * FROM metaschema_modules_public.compute_log_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('db_usage_module', `SELECT * FROM metaschema_modules_public.db_usage_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('storage_log_module', `SELECT * FROM metaschema_modules_public.storage_log_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('transfer_log_module', `SELECT * FROM metaschema_modules_public.transfer_log_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('webauthn_auth_module', `SELECT * FROM metaschema_modules_public.webauthn_auth_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('webauthn_credentials_module', `SELECT * FROM metaschema_modules_public.webauthn_credentials_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('inference_log_module', `SELECT * FROM metaschema_modules_public.inference_log_module WHERE database_id = $1 ORDER BY id`); - await queryAndParse('rate_limit_meters_module', `SELECT * FROM metaschema_modules_public.rate_limit_meters_module WHERE database_id = $1 ORDER BY id`); + // Iterate the generated table manifest (already topologically sorted by FK + // dependencies). All tables are keyed by database_id except `database` + // itself, which is keyed by id. + for (const key of META_TABLE_ORDER) { + const tableConfig = META_TABLE_CONFIG[key]; + const filterColumn = key === 'database' ? 'id' : 'database_id'; + await queryAndParse(key, `SELECT * FROM ${tableConfig.schema}.${tableConfig.table} WHERE ${filterColumn} = $1 ORDER BY id`); + } return sql; }; diff --git a/pgpm/export/src/export-utils.ts b/pgpm/export/src/export-utils.ts index 26c63f829..158ac26ed 100644 --- a/pgpm/export/src/export-utils.ts +++ b/pgpm/export/src/export-utils.ts @@ -6,6 +6,7 @@ import path from 'path'; import { PgpmPackage, getMissingInstallableModules, parseAuthor } from '@pgpmjs/core'; import { lookupByPgUdt } from './type-map'; +import metaExportTables from './meta-export-tables.json'; // ============================================================================= // Shared constants @@ -89,111 +90,6 @@ $LQLMIGRATION$;`; export const META_COMMON_FOOTER = ` SET session_replication_role TO DEFAULT;`; -/** - * Ordered list of meta tables for export. - * Tables are processed in this order to satisfy foreign key dependencies. - */ -export const META_TABLE_ORDER = [ - 'database', - 'schema', - 'function', - 'table', - 'field', - 'spatial_relation', - 'policy', - 'index', - 'trigger', - 'trigger_function', - 'rls_function', - 'foreign_key_constraint', - 'primary_key_constraint', - 'unique_constraint', - 'check_constraint', - 'full_text_search', - 'schema_grant', - 'table_grant', - 'default_privilege', - 'domains', - 'sites', - 'apis', - 'apps', - 'site_modules', - 'site_themes', - 'site_metadata', - 'api_modules', - 'api_extensions', - 'api_schemas', - 'database_settings', - 'api_settings', - 'rls_settings', - 'cors_settings', - 'pubkey_settings', - 'webauthn_settings', - 'rls_module', - 'user_auth_module', - 'memberships_module', - 'permissions_module', - 'limits_module', - 'levels_module', - 'events_module', - 'users_module', - 'hierarchy_module', - 'membership_types_module', - 'invites_module', - 'emails_module', - 'sessions_module', - 'user_state_module', - 'profiles_module', - 'config_secrets_user_module', - 'user_credentials_module', - 'user_settings_module', - 'connected_accounts_module', - 'phone_numbers_module', - 'crypto_addresses_module', - 'crypto_auth_module', - 'field_module', - 'table_module', - 'secure_table_provision', - 'uuid_module', - 'default_ids_module', - 'denormalized_table_field', - // NOTE: blueprint_template, blueprint, and blueprint_construction are intentionally - // excluded from the export flow — they are runtime-only tables not exported as metadata. - 'relation_provision', - 'entity_type_provision', - 'rate_limits_module', - 'storage_module', - 'billing_module', - 'billing_provider_module', - 'devices_module', - 'identity_providers_module', - 'integration_providers_module', - 'notifications_module', - 'plans_module', - 'realtime_module', - 'session_secrets_module', - 'infra_secrets_module', - 'infra_config_module', - 'internal_secrets_module', - 'i18n_module', - 'agent_module', - 'function_module', - 'namespace_module', - 'merkle_store_module', - 'graph_module', - 'graph_execution_module', - 'function_deployment_module', - 'function_invocation_module', - 'compute_log_module', - 'db_usage_module', - 'storage_log_module', - 'transfer_log_module', - 'webauthn_auth_module', - 'webauthn_credentials_module', - 'inference_log_module', - 'rate_limit_meters_module' -] as const; - // ============================================================================= // Shared types for table config // ============================================================================= @@ -215,103 +111,28 @@ export interface TableConfig { } /** - * Shared metadata table configuration. - * - * Fields are discovered dynamically at runtime via introspection: - * - SQL flow: uses information_schema.columns + mapPgTypeToFieldType() - * - GraphQL flow: uses __type introspection + mapGraphQLTypeToFieldType() - * - * Only `typeOverrides` are hardcoded for special types (image, upload, url) - * that cannot be inferred from database/GraphQL types alone. - * + * A single entry in the generated meta export table manifest + * (meta-export-tables.json, generated by constructive-db and propagated + * here via constructive-hub's schema-propagation workflow). */ -export const META_TABLE_CONFIG: Record = { - // ============================================================================= - // metaschema_public tables - // ============================================================================= - database: { - schema: 'metaschema_public', - table: 'database' - }, - schema: { - schema: 'metaschema_public', - table: 'schema' - }, - function: { - schema: 'metaschema_public', - table: 'function' - }, - table: { - schema: 'metaschema_public', - table: 'table' - }, +export interface MetaExportTableEntry { + key: string; + schema: string; + table: string; +} + +/** + * Hand-authored per-table overrides layered on top of the generated + * table manifest. Only exceptional exporter behavior lives here: + * conflict handling, special field types (image, upload, url) that + * cannot be inferred, GraphQL type name overrides, and columns whose + * values must come from DDL defaults at deploy time. + */ +export const META_TABLE_OVERRIDES: Record> = { field: { - schema: 'metaschema_public', - table: 'field', conflictDoNothing: true }, - policy: { - schema: 'metaschema_public', - table: 'policy' - }, - index: { - schema: 'metaschema_public', - table: 'index' - }, - trigger: { - schema: 'metaschema_public', - table: 'trigger' - }, - trigger_function: { - schema: 'metaschema_public', - table: 'trigger_function' - }, - rls_function: { - schema: 'metaschema_public', - table: 'rls_function' - }, - foreign_key_constraint: { - schema: 'metaschema_public', - table: 'foreign_key_constraint' - }, - primary_key_constraint: { - schema: 'metaschema_public', - table: 'primary_key_constraint' - }, - unique_constraint: { - schema: 'metaschema_public', - table: 'unique_constraint' - }, - check_constraint: { - schema: 'metaschema_public', - table: 'check_constraint' - }, - full_text_search: { - schema: 'metaschema_public', - table: 'full_text_search' - }, - schema_grant: { - schema: 'metaschema_public', - table: 'schema_grant' - }, - table_grant: { - schema: 'metaschema_public', - table: 'table_grant' - }, - default_privilege: { - schema: 'metaschema_public', - table: 'default_privilege' - }, - // ============================================================================= - // services_public tables - // ============================================================================= - domains: { - schema: 'services_public', - table: 'domains' - }, sites: { - schema: 'services_public', - table: 'sites', typeOverrides: { og_image: 'image', favicon: 'upload', @@ -323,327 +144,52 @@ export const META_TABLE_CONFIG: Record = { } }, apis: { - schema: 'services_public', - table: 'apis', columnDefaults: { dbname: 'current_database()' } }, apps: { - schema: 'services_public', - table: 'apps', typeOverrides: { app_image: 'image', app_store_link: 'url', play_store_link: 'url' } }, - site_modules: { - schema: 'services_public', - table: 'site_modules' - }, - site_themes: { - schema: 'services_public', - table: 'site_themes' - }, site_metadata: { - schema: 'services_public', - table: 'site_metadata', typeOverrides: { og_image: 'image' } }, - api_modules: { - schema: 'services_public', - table: 'api_modules' - }, - api_extensions: { - schema: 'services_public', - table: 'api_extensions' - }, - api_schemas: { - schema: 'services_public', - table: 'api_schemas' - }, - database_settings: { - schema: 'services_public', - table: 'database_settings' - }, - api_settings: { - schema: 'services_public', - table: 'api_settings' - }, - rls_settings: { - schema: 'services_public', - table: 'rls_settings' - }, - cors_settings: { - schema: 'services_public', - table: 'cors_settings' - }, - pubkey_settings: { - schema: 'services_public', - table: 'pubkey_settings' - }, - webauthn_settings: { - schema: 'services_public', - table: 'webauthn_settings' - }, - // ============================================================================= - // metaschema_modules_public tables - // ============================================================================= - rls_module: { - schema: 'metaschema_modules_public', - table: 'rls_module' - }, - user_auth_module: { - schema: 'metaschema_modules_public', - table: 'user_auth_module' - }, - memberships_module: { - schema: 'metaschema_modules_public', - table: 'memberships_module' - }, - permissions_module: { - schema: 'metaschema_modules_public', - table: 'permissions_module' - }, - limits_module: { - schema: 'metaschema_modules_public', - table: 'limits_module' - }, - levels_module: { - schema: 'metaschema_modules_public', - table: 'levels_module' - }, - events_module: { - schema: 'metaschema_modules_public', - table: 'events_module' - }, - users_module: { - schema: 'metaschema_modules_public', - table: 'users_module' - }, - hierarchy_module: { - schema: 'metaschema_modules_public', - table: 'hierarchy_module' - }, - membership_types_module: { - schema: 'metaschema_modules_public', - table: 'membership_types_module' - }, - invites_module: { - schema: 'metaschema_modules_public', - table: 'invites_module' - }, - emails_module: { - schema: 'metaschema_modules_public', - table: 'emails_module' - }, - sessions_module: { - schema: 'metaschema_modules_public', - table: 'sessions_module' - }, - user_state_module: { - schema: 'metaschema_modules_public', - table: 'user_state_module' - }, - profiles_module: { - schema: 'metaschema_modules_public', - table: 'profiles_module' - }, - config_secrets_user_module: { - schema: 'metaschema_modules_public', - table: 'config_secrets_user_module' - }, - user_credentials_module: { - schema: 'metaschema_modules_public', - table: 'user_credentials_module' - }, - user_settings_module: { - schema: 'metaschema_modules_public', - table: 'user_settings_module' - }, - connected_accounts_module: { - schema: 'metaschema_modules_public', - table: 'connected_accounts_module' - }, - phone_numbers_module: { - schema: 'metaschema_modules_public', - table: 'phone_numbers_module' - }, - crypto_addresses_module: { - schema: 'metaschema_modules_public', - table: 'crypto_addresses_module' - }, - crypto_auth_module: { - schema: 'metaschema_modules_public', - table: 'crypto_auth_module' - }, - field_module: { - schema: 'metaschema_modules_public', - table: 'field_module' - }, - table_module: { - schema: 'metaschema_modules_public', - table: 'table_module' - }, - // NOTE: table_template_module has been removed from pgpm-modules (superseded by blueprints) - secure_table_provision: { - schema: 'metaschema_modules_public', - table: 'secure_table_provision' - }, - uuid_module: { - schema: 'metaschema_modules_public', - table: 'uuid_module' - }, - default_ids_module: { - schema: 'metaschema_modules_public', - table: 'default_ids_module' - }, - denormalized_table_field: { - schema: 'metaschema_modules_public', - table: 'denormalized_table_field' - }, - relation_provision: { - schema: 'metaschema_modules_public', - table: 'relation_provision' - }, - entity_type_provision: { - schema: 'metaschema_modules_public', - table: 'entity_type_provision' - }, - rate_limits_module: { - schema: 'metaschema_modules_public', - table: 'rate_limits_module' - }, - storage_module: { - schema: 'metaschema_modules_public', - table: 'storage_module' - }, - billing_module: { - schema: 'metaschema_modules_public', - table: 'billing_module' - }, - billing_provider_module: { - schema: 'metaschema_modules_public', - table: 'billing_provider_module' - }, - devices_module: { - schema: 'metaschema_modules_public', - table: 'devices_module' - }, - identity_providers_module: { - schema: 'metaschema_modules_public', - table: 'identity_providers_module' - }, - integration_providers_module: { - schema: 'metaschema_modules_public', - table: 'integration_providers_module' - }, - notifications_module: { - schema: 'metaschema_modules_public', - table: 'notifications_module' - }, - plans_module: { - schema: 'metaschema_modules_public', - table: 'plans_module' - }, - realtime_module: { - schema: 'metaschema_modules_public', - table: 'realtime_module' - }, - session_secrets_module: { - schema: 'metaschema_modules_public', - table: 'session_secrets_module' - }, - infra_secrets_module: { - schema: 'metaschema_modules_public', - table: 'infra_secrets_module' - }, - infra_config_module: { - schema: 'metaschema_modules_public', - table: 'infra_config_module' - }, - internal_secrets_module: { - schema: 'metaschema_modules_public', - table: 'internal_secrets_module' - }, i18n_module: { - schema: 'metaschema_modules_public', - table: 'i18n_module', gqlTypeName: 'I18NModule' // i18n is a well-known abbreviation; PostGraphile inflector capitalizes the N - }, - agent_module: { - schema: 'metaschema_modules_public', - table: 'agent_module' - }, - function_module: { - schema: 'metaschema_modules_public', - table: 'function_module' - }, - namespace_module: { - schema: 'metaschema_modules_public', - table: 'namespace_module' - }, - merkle_store_module: { - schema: 'metaschema_modules_public', - table: 'merkle_store_module' - }, - graph_module: { - schema: 'metaschema_modules_public', - table: 'graph_module' - }, - graph_execution_module: { - schema: 'metaschema_modules_public', - table: 'graph_execution_module' - }, - function_deployment_module: { - schema: 'metaschema_modules_public', - table: 'function_deployment_module' - }, - function_invocation_module: { - schema: 'metaschema_modules_public', - table: 'function_invocation_module' - }, - compute_log_module: { - schema: 'metaschema_modules_public', - table: 'compute_log_module' - }, - db_usage_module: { - schema: 'metaschema_modules_public', - table: 'db_usage_module' - }, - storage_log_module: { - schema: 'metaschema_modules_public', - table: 'storage_log_module' - }, - transfer_log_module: { - schema: 'metaschema_modules_public', - table: 'transfer_log_module' - }, - webauthn_auth_module: { - schema: 'metaschema_modules_public', - table: 'webauthn_auth_module' - }, - webauthn_credentials_module: { - schema: 'metaschema_modules_public', - table: 'webauthn_credentials_module' - }, - inference_log_module: { - schema: 'metaschema_modules_public', - table: 'inference_log_module', - }, - rate_limit_meters_module: { - schema: 'metaschema_modules_public', - table: 'rate_limit_meters_module', - }, - spatial_relation: { - schema: 'metaschema_public', - table: 'spatial_relation' } }; +/** + * Ordered list of meta tables for export, derived from the generated + * manifest. Tables are already topologically sorted by foreign key + * dependencies at generation time. + */ +export const META_TABLE_ORDER: string[] = (metaExportTables as { tables: MetaExportTableEntry[] }).tables.map(t => t.key); + +/** + * Shared metadata table configuration, built from the generated manifest + * plus META_TABLE_OVERRIDES. + * + * Fields are discovered dynamically at runtime via introspection: + * - SQL flow: uses information_schema.columns + mapPgTypeToFieldType() + * - GraphQL flow: uses __type introspection + mapGraphQLTypeToFieldType() + * + * Only `typeOverrides` are hardcoded for special types (image, upload, url) + * that cannot be inferred from database/GraphQL types alone. + */ +export const META_TABLE_CONFIG: Record = Object.fromEntries( + (metaExportTables as { tables: MetaExportTableEntry[] }).tables.map(t => [ + t.key, + { schema: t.schema, table: t.table, ...META_TABLE_OVERRIDES[t.key] } + ]) +); + // ============================================================================= // Shared interfaces // ============================================================================= diff --git a/pgpm/export/src/index.ts b/pgpm/export/src/index.ts index b357a3d2a..bcc743c44 100644 --- a/pgpm/export/src/index.ts +++ b/pgpm/export/src/index.ts @@ -11,6 +11,7 @@ export { META_COMMON_FOOTER, META_TABLE_ORDER, META_TABLE_CONFIG, + META_TABLE_OVERRIDES, mapPgTypeToFieldType, makeReplacer, preparePackage, @@ -21,6 +22,7 @@ export { export type { FieldType, TableConfig, + MetaExportTableEntry, Schema, MakeReplacerOptions, ReplacerResult, diff --git a/pgpm/export/src/meta-export-tables.json b/pgpm/export/src/meta-export-tables.json new file mode 100644 index 000000000..d43db2390 --- /dev/null +++ b/pgpm/export/src/meta-export-tables.json @@ -0,0 +1,505 @@ +{ + "$comment": "Generated by constructive-db (pnpm run generate:constructive). Do not edit. Consumed by @pgpmjs/export.", + "tables": [ + { + "key": "database", + "schema": "metaschema_public", + "table": "database" + }, + { + "key": "schema", + "schema": "metaschema_public", + "table": "schema" + }, + { + "key": "trigger_function", + "schema": "metaschema_public", + "table": "trigger_function" + }, + { + "key": "apis", + "schema": "services_public", + "table": "apis" + }, + { + "key": "database_settings", + "schema": "services_public", + "table": "database_settings" + }, + { + "key": "sites", + "schema": "services_public", + "table": "sites" + }, + { + "key": "default_ids_module", + "schema": "metaschema_modules_public", + "table": "default_ids_module" + }, + { + "key": "entity_type_provision", + "schema": "metaschema_modules_public", + "table": "entity_type_provision" + }, + { + "key": "composite_type", + "schema": "metaschema_public", + "table": "composite_type" + }, + { + "key": "default_privilege", + "schema": "metaschema_public", + "table": "default_privilege" + }, + { + "key": "enum", + "schema": "metaschema_public", + "table": "enum" + }, + { + "key": "function", + "schema": "metaschema_public", + "table": "function" + }, + { + "key": "schema_grant", + "schema": "metaschema_public", + "table": "schema_grant" + }, + { + "key": "table", + "schema": "metaschema_public", + "table": "table" + }, + { + "key": "api_modules", + "schema": "services_public", + "table": "api_modules" + }, + { + "key": "api_schemas", + "schema": "services_public", + "table": "api_schemas" + }, + { + "key": "api_settings", + "schema": "services_public", + "table": "api_settings" + }, + { + "key": "apps", + "schema": "services_public", + "table": "apps" + }, + { + "key": "cors_settings", + "schema": "services_public", + "table": "cors_settings" + }, + { + "key": "domains", + "schema": "services_public", + "table": "domains" + }, + { + "key": "site_metadata", + "schema": "services_public", + "table": "site_metadata" + }, + { + "key": "site_modules", + "schema": "services_public", + "table": "site_modules" + }, + { + "key": "site_themes", + "schema": "services_public", + "table": "site_themes" + }, + { + "key": "check_constraint", + "schema": "metaschema_public", + "table": "check_constraint" + }, + { + "key": "field", + "schema": "metaschema_public", + "table": "field" + }, + { + "key": "foreign_key_constraint", + "schema": "metaschema_public", + "table": "foreign_key_constraint" + }, + { + "key": "full_text_search", + "schema": "metaschema_public", + "table": "full_text_search" + }, + { + "key": "index", + "schema": "metaschema_public", + "table": "index" + }, + { + "key": "policy", + "schema": "metaschema_public", + "table": "policy" + }, + { + "key": "primary_key_constraint", + "schema": "metaschema_public", + "table": "primary_key_constraint" + }, + { + "key": "table_grant", + "schema": "metaschema_public", + "table": "table_grant" + }, + { + "key": "trigger", + "schema": "metaschema_public", + "table": "trigger" + }, + { + "key": "unique_constraint", + "schema": "metaschema_public", + "table": "unique_constraint" + }, + { + "key": "view", + "schema": "metaschema_public", + "table": "view" + }, + { + "key": "pubkey_settings", + "schema": "services_public", + "table": "pubkey_settings" + }, + { + "key": "rls_settings", + "schema": "services_public", + "table": "rls_settings" + }, + { + "key": "agent_module", + "schema": "metaschema_modules_public", + "table": "agent_module" + }, + { + "key": "billing_module", + "schema": "metaschema_modules_public", + "table": "billing_module" + }, + { + "key": "billing_provider_module", + "schema": "metaschema_modules_public", + "table": "billing_provider_module" + }, + { + "key": "compute_log_module", + "schema": "metaschema_modules_public", + "table": "compute_log_module" + }, + { + "key": "config_secrets_user_module", + "schema": "metaschema_modules_public", + "table": "config_secrets_user_module" + }, + { + "key": "connected_accounts_module", + "schema": "metaschema_modules_public", + "table": "connected_accounts_module" + }, + { + "key": "crypto_addresses_module", + "schema": "metaschema_modules_public", + "table": "crypto_addresses_module" + }, + { + "key": "crypto_auth_module", + "schema": "metaschema_modules_public", + "table": "crypto_auth_module" + }, + { + "key": "db_usage_module", + "schema": "metaschema_modules_public", + "table": "db_usage_module" + }, + { + "key": "devices_module", + "schema": "metaschema_modules_public", + "table": "devices_module" + }, + { + "key": "emails_module", + "schema": "metaschema_modules_public", + "table": "emails_module" + }, + { + "key": "events_module", + "schema": "metaschema_modules_public", + "table": "events_module" + }, + { + "key": "function_invocation_module", + "schema": "metaschema_modules_public", + "table": "function_invocation_module" + }, + { + "key": "function_module", + "schema": "metaschema_modules_public", + "table": "function_module" + }, + { + "key": "hierarchy_module", + "schema": "metaschema_modules_public", + "table": "hierarchy_module" + }, + { + "key": "i18n_module", + "schema": "metaschema_modules_public", + "table": "i18n_module" + }, + { + "key": "identity_providers_module", + "schema": "metaschema_modules_public", + "table": "identity_providers_module" + }, + { + "key": "inference_log_module", + "schema": "metaschema_modules_public", + "table": "inference_log_module" + }, + { + "key": "infra_config_module", + "schema": "metaschema_modules_public", + "table": "infra_config_module" + }, + { + "key": "infra_secrets_module", + "schema": "metaschema_modules_public", + "table": "infra_secrets_module" + }, + { + "key": "internal_secrets_module", + "schema": "metaschema_modules_public", + "table": "internal_secrets_module" + }, + { + "key": "invites_module", + "schema": "metaschema_modules_public", + "table": "invites_module" + }, + { + "key": "limits_module", + "schema": "metaschema_modules_public", + "table": "limits_module" + }, + { + "key": "membership_types_module", + "schema": "metaschema_modules_public", + "table": "membership_types_module" + }, + { + "key": "merkle_store_module", + "schema": "metaschema_modules_public", + "table": "merkle_store_module" + }, + { + "key": "namespace_module", + "schema": "metaschema_modules_public", + "table": "namespace_module" + }, + { + "key": "notifications_module", + "schema": "metaschema_modules_public", + "table": "notifications_module" + }, + { + "key": "permissions_module", + "schema": "metaschema_modules_public", + "table": "permissions_module" + }, + { + "key": "phone_numbers_module", + "schema": "metaschema_modules_public", + "table": "phone_numbers_module" + }, + { + "key": "plans_module", + "schema": "metaschema_modules_public", + "table": "plans_module" + }, + { + "key": "principal_auth_module", + "schema": "metaschema_modules_public", + "table": "principal_auth_module" + }, + { + "key": "profiles_module", + "schema": "metaschema_modules_public", + "table": "profiles_module" + }, + { + "key": "rate_limit_meters_module", + "schema": "metaschema_modules_public", + "table": "rate_limit_meters_module" + }, + { + "key": "rate_limits_module", + "schema": "metaschema_modules_public", + "table": "rate_limits_module" + }, + { + "key": "realtime_module", + "schema": "metaschema_modules_public", + "table": "realtime_module" + }, + { + "key": "relation_provision", + "schema": "metaschema_modules_public", + "table": "relation_provision" + }, + { + "key": "rls_module", + "schema": "metaschema_modules_public", + "table": "rls_module" + }, + { + "key": "secure_table_provision", + "schema": "metaschema_modules_public", + "table": "secure_table_provision" + }, + { + "key": "session_secrets_module", + "schema": "metaschema_modules_public", + "table": "session_secrets_module" + }, + { + "key": "sessions_module", + "schema": "metaschema_modules_public", + "table": "sessions_module" + }, + { + "key": "storage_log_module", + "schema": "metaschema_modules_public", + "table": "storage_log_module" + }, + { + "key": "storage_module", + "schema": "metaschema_modules_public", + "table": "storage_module" + }, + { + "key": "transfer_log_module", + "schema": "metaschema_modules_public", + "table": "transfer_log_module" + }, + { + "key": "user_auth_module", + "schema": "metaschema_modules_public", + "table": "user_auth_module" + }, + { + "key": "user_credentials_module", + "schema": "metaschema_modules_public", + "table": "user_credentials_module" + }, + { + "key": "user_settings_module", + "schema": "metaschema_modules_public", + "table": "user_settings_module" + }, + { + "key": "user_state_module", + "schema": "metaschema_modules_public", + "table": "user_state_module" + }, + { + "key": "users_module", + "schema": "metaschema_modules_public", + "table": "users_module" + }, + { + "key": "webauthn_auth_module", + "schema": "metaschema_modules_public", + "table": "webauthn_auth_module" + }, + { + "key": "webauthn_credentials_module", + "schema": "metaschema_modules_public", + "table": "webauthn_credentials_module" + }, + { + "key": "embedding_chunks", + "schema": "metaschema_public", + "table": "embedding_chunks" + }, + { + "key": "partition", + "schema": "metaschema_public", + "table": "partition" + }, + { + "key": "spatial_relation", + "schema": "metaschema_public", + "table": "spatial_relation" + }, + { + "key": "view_grant", + "schema": "metaschema_public", + "table": "view_grant" + }, + { + "key": "view_rule", + "schema": "metaschema_public", + "table": "view_rule" + }, + { + "key": "view_table", + "schema": "metaschema_public", + "table": "view_table" + }, + { + "key": "webauthn_settings", + "schema": "services_public", + "table": "webauthn_settings" + }, + { + "key": "db_preset_module", + "schema": "metaschema_modules_public", + "table": "db_preset_module" + }, + { + "key": "denormalized_table_field", + "schema": "metaschema_modules_public", + "table": "denormalized_table_field" + }, + { + "key": "function_deployment_module", + "schema": "metaschema_modules_public", + "table": "function_deployment_module" + }, + { + "key": "graph_module", + "schema": "metaschema_modules_public", + "table": "graph_module" + }, + { + "key": "memberships_module", + "schema": "metaschema_modules_public", + "table": "memberships_module" + }, + { + "key": "resource_module", + "schema": "metaschema_modules_public", + "table": "resource_module" + }, + { + "key": "graph_execution_module", + "schema": "metaschema_modules_public", + "table": "graph_execution_module" + } + ] +}