@constructive-io/graphql-codegen 2.32.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +429 -1691
- package/cli/index.d.ts +5 -2
- package/cli/index.js +98 -581
- package/cli/shared.d.ts +35 -0
- package/cli/shared.js +106 -0
- package/{esm/cli → core}/codegen/barrel.d.ts +1 -1
- package/{cli → core}/codegen/barrel.js +1 -4
- package/{esm/cli → core}/codegen/index.d.ts +15 -5
- package/{cli → core}/codegen/index.js +44 -24
- package/{cli → core}/codegen/invalidation.d.ts +2 -2
- package/{esm/cli → core}/codegen/mutation-keys.d.ts +2 -2
- package/{cli → core}/codegen/orm/client-generator.js +2 -3
- package/{esm/cli → core}/codegen/orm/index.d.ts +9 -2
- package/{cli → core}/codegen/orm/index.js +3 -2
- package/{cli → core}/codegen/query-keys.d.ts +2 -2
- package/core/codegen/shared/index.d.ts +39 -0
- package/core/codegen/shared/index.js +118 -0
- package/core/config/index.d.ts +5 -0
- package/core/config/index.js +13 -0
- package/core/config/loader.d.ts +18 -0
- package/{cli/commands/init.js → core/config/loader.js} +7 -94
- package/core/config/resolver.d.ts +46 -0
- package/core/config/resolver.js +104 -0
- package/core/database/index.d.ts +43 -0
- package/core/database/index.js +85 -0
- package/core/generate.d.ts +22 -0
- package/core/generate.js +192 -0
- package/core/index.d.ts +13 -1
- package/core/index.js +22 -2
- package/{cli → core}/introspect/fetch-schema.js +58 -9
- package/core/introspect/source/api-schemas.d.ts +44 -0
- package/core/introspect/source/api-schemas.js +122 -0
- package/core/introspect/source/database.d.ts +32 -0
- package/core/introspect/source/database.js +91 -0
- package/core/introspect/source/index.d.ts +112 -0
- package/core/introspect/source/index.js +173 -0
- package/core/introspect/source/pgpm-module.d.ts +83 -0
- package/core/introspect/source/pgpm-module.js +200 -0
- package/core/output/index.d.ts +4 -0
- package/core/output/index.js +9 -0
- package/core/output/writer.d.ts +38 -0
- package/core/output/writer.js +156 -0
- package/{cli/commands/shared.d.ts → core/pipeline/index.d.ts} +5 -3
- package/{cli/commands/shared.js → core/pipeline/index.js} +4 -0
- package/{cli → core}/watch/orchestrator.d.ts +25 -3
- package/{cli → core}/watch/orchestrator.js +35 -27
- package/{cli → core}/watch/types.d.ts +1 -1
- package/esm/cli/index.d.ts +5 -2
- package/esm/cli/index.js +97 -547
- package/esm/cli/shared.d.ts +35 -0
- package/esm/cli/shared.js +101 -0
- package/{cli → esm/core}/codegen/barrel.d.ts +1 -1
- package/esm/{cli → core}/codegen/barrel.js +1 -4
- package/{cli → esm/core}/codegen/index.d.ts +15 -5
- package/esm/{cli → core}/codegen/index.js +44 -24
- package/esm/{cli → core}/codegen/invalidation.d.ts +2 -2
- package/{cli → esm/core}/codegen/mutation-keys.d.ts +2 -2
- package/esm/{cli → core}/codegen/orm/client-generator.js +2 -3
- package/{cli → esm/core}/codegen/orm/index.d.ts +9 -2
- package/esm/{cli → core}/codegen/orm/index.js +3 -2
- package/esm/{cli → core}/codegen/query-keys.d.ts +2 -2
- package/esm/core/codegen/shared/index.d.ts +39 -0
- package/esm/core/codegen/shared/index.js +79 -0
- package/esm/core/config/index.d.ts +5 -0
- package/esm/core/config/index.js +5 -0
- package/esm/core/config/loader.d.ts +18 -0
- package/esm/core/config/loader.js +71 -0
- package/esm/core/config/resolver.d.ts +46 -0
- package/esm/core/config/resolver.js +100 -0
- package/esm/core/database/index.d.ts +43 -0
- package/esm/core/database/index.js +48 -0
- package/esm/core/generate.d.ts +22 -0
- package/esm/core/generate.js +186 -0
- package/esm/core/index.d.ts +13 -1
- package/esm/core/index.js +20 -1
- package/esm/{cli → core}/introspect/fetch-schema.js +55 -9
- package/esm/core/introspect/source/api-schemas.d.ts +44 -0
- package/esm/core/introspect/source/api-schemas.js +117 -0
- package/esm/core/introspect/source/database.d.ts +32 -0
- package/esm/core/introspect/source/database.js +87 -0
- package/esm/core/introspect/source/index.d.ts +112 -0
- package/esm/core/introspect/source/index.js +154 -0
- package/esm/core/introspect/source/pgpm-module.d.ts +83 -0
- package/esm/core/introspect/source/pgpm-module.js +194 -0
- package/esm/core/output/index.d.ts +4 -0
- package/esm/core/output/index.js +4 -0
- package/esm/core/output/writer.d.ts +38 -0
- package/esm/core/output/writer.js +119 -0
- package/esm/{cli/commands/shared.d.ts → core/pipeline/index.d.ts} +5 -3
- package/esm/{cli/commands/shared.js → core/pipeline/index.js} +1 -0
- package/esm/{cli → core}/watch/orchestrator.d.ts +25 -3
- package/esm/{cli → core}/watch/orchestrator.js +35 -27
- package/esm/{cli → core}/watch/types.d.ts +1 -1
- package/esm/index.d.ts +8 -3
- package/esm/index.js +9 -3
- package/esm/types/config.d.ts +101 -138
- package/esm/types/config.js +8 -35
- package/esm/types/index.d.ts +2 -2
- package/esm/types/index.js +1 -1
- package/index.d.ts +8 -3
- package/index.js +18 -8
- package/package.json +18 -11
- package/types/config.d.ts +101 -138
- package/types/config.js +9 -38
- package/types/index.d.ts +2 -2
- package/types/index.js +3 -3
- package/cli/commands/generate-orm.d.ts +0 -53
- package/cli/commands/generate-orm.js +0 -292
- package/cli/commands/generate.d.ts +0 -66
- package/cli/commands/generate.js +0 -431
- package/cli/commands/index.d.ts +0 -9
- package/cli/commands/index.js +0 -14
- package/cli/commands/init.d.ts +0 -35
- package/cli/introspect/source/index.d.ts +0 -48
- package/cli/introspect/source/index.js +0 -72
- package/esm/cli/commands/generate-orm.d.ts +0 -53
- package/esm/cli/commands/generate-orm.js +0 -289
- package/esm/cli/commands/generate.d.ts +0 -66
- package/esm/cli/commands/generate.js +0 -393
- package/esm/cli/commands/index.d.ts +0 -9
- package/esm/cli/commands/index.js +0 -6
- package/esm/cli/commands/init.d.ts +0 -35
- package/esm/cli/commands/init.js +0 -158
- package/esm/cli/introspect/source/index.d.ts +0 -48
- package/esm/cli/introspect/source/index.js +0 -54
- /package/{cli → core}/codegen/babel-ast.d.ts +0 -0
- /package/{cli → core}/codegen/babel-ast.js +0 -0
- /package/{cli → core}/codegen/client.d.ts +0 -0
- /package/{cli → core}/codegen/client.js +0 -0
- /package/{cli → core}/codegen/custom-mutations.d.ts +0 -0
- /package/{cli → core}/codegen/custom-mutations.js +0 -0
- /package/{cli → core}/codegen/custom-queries.d.ts +0 -0
- /package/{cli → core}/codegen/custom-queries.js +0 -0
- /package/{cli → core}/codegen/gql-ast.d.ts +0 -0
- /package/{cli → core}/codegen/gql-ast.js +0 -0
- /package/{cli → core}/codegen/invalidation.js +0 -0
- /package/{cli → core}/codegen/mutation-keys.js +0 -0
- /package/{cli → core}/codegen/mutations.d.ts +0 -0
- /package/{cli → core}/codegen/mutations.js +0 -0
- /package/{cli → core}/codegen/orm/barrel.d.ts +0 -0
- /package/{cli → core}/codegen/orm/barrel.js +0 -0
- /package/{cli → core}/codegen/orm/client-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/client.d.ts +0 -0
- /package/{cli → core}/codegen/orm/client.js +0 -0
- /package/{cli → core}/codegen/orm/custom-ops-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/custom-ops-generator.js +0 -0
- /package/{cli → core}/codegen/orm/input-types-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/input-types-generator.js +0 -0
- /package/{cli → core}/codegen/orm/model-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/model-generator.js +0 -0
- /package/{cli → core}/codegen/orm/query-builder.d.ts +0 -0
- /package/{cli → core}/codegen/orm/query-builder.js +0 -0
- /package/{cli → core}/codegen/orm/query-builder.ts +0 -0
- /package/{cli → core}/codegen/orm/select-types.d.ts +0 -0
- /package/{cli → core}/codegen/orm/select-types.js +0 -0
- /package/{cli → core}/codegen/queries.d.ts +0 -0
- /package/{cli → core}/codegen/queries.js +0 -0
- /package/{cli → core}/codegen/query-keys.js +0 -0
- /package/{cli → core}/codegen/scalars.d.ts +0 -0
- /package/{cli → core}/codegen/scalars.js +0 -0
- /package/{cli → core}/codegen/schema-gql-ast.d.ts +0 -0
- /package/{cli → core}/codegen/schema-gql-ast.js +0 -0
- /package/{cli → core}/codegen/schema-types-generator.d.ts +0 -0
- /package/{cli → core}/codegen/schema-types-generator.js +0 -0
- /package/{cli → core}/codegen/type-resolver.d.ts +0 -0
- /package/{cli → core}/codegen/type-resolver.js +0 -0
- /package/{cli → core}/codegen/types.d.ts +0 -0
- /package/{cli → core}/codegen/types.js +0 -0
- /package/{cli → core}/codegen/utils.d.ts +0 -0
- /package/{cli → core}/codegen/utils.js +0 -0
- /package/{cli → core}/introspect/fetch-schema.d.ts +0 -0
- /package/{cli → core}/introspect/index.d.ts +0 -0
- /package/{cli → core}/introspect/index.js +0 -0
- /package/{cli → core}/introspect/infer-tables.d.ts +0 -0
- /package/{cli → core}/introspect/infer-tables.js +0 -0
- /package/{cli → core}/introspect/schema-query.d.ts +0 -0
- /package/{cli → core}/introspect/schema-query.js +0 -0
- /package/{cli → core}/introspect/source/endpoint.d.ts +0 -0
- /package/{cli → core}/introspect/source/endpoint.js +0 -0
- /package/{cli → core}/introspect/source/file.d.ts +0 -0
- /package/{cli → core}/introspect/source/file.js +0 -0
- /package/{cli → core}/introspect/source/types.d.ts +0 -0
- /package/{cli → core}/introspect/source/types.js +0 -0
- /package/{cli → core}/introspect/transform-schema.d.ts +0 -0
- /package/{cli → core}/introspect/transform-schema.js +0 -0
- /package/{cli → core}/introspect/transform.d.ts +0 -0
- /package/{cli → core}/introspect/transform.js +0 -0
- /package/{cli → core}/watch/cache.d.ts +0 -0
- /package/{cli → core}/watch/cache.js +0 -0
- /package/{cli → core}/watch/debounce.d.ts +0 -0
- /package/{cli → core}/watch/debounce.js +0 -0
- /package/{cli → core}/watch/hash.d.ts +0 -0
- /package/{cli → core}/watch/hash.js +0 -0
- /package/{cli → core}/watch/index.d.ts +0 -0
- /package/{cli → core}/watch/index.js +0 -0
- /package/{cli → core}/watch/poller.d.ts +0 -0
- /package/{cli → core}/watch/poller.js +0 -0
- /package/{cli → core}/watch/types.js +0 -0
- /package/esm/{cli → core}/codegen/babel-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/babel-ast.js +0 -0
- /package/esm/{cli → core}/codegen/client.d.ts +0 -0
- /package/esm/{cli → core}/codegen/client.js +0 -0
- /package/esm/{cli → core}/codegen/custom-mutations.d.ts +0 -0
- /package/esm/{cli → core}/codegen/custom-mutations.js +0 -0
- /package/esm/{cli → core}/codegen/custom-queries.d.ts +0 -0
- /package/esm/{cli → core}/codegen/custom-queries.js +0 -0
- /package/esm/{cli → core}/codegen/gql-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/gql-ast.js +0 -0
- /package/esm/{cli → core}/codegen/invalidation.js +0 -0
- /package/esm/{cli → core}/codegen/mutation-keys.js +0 -0
- /package/esm/{cli → core}/codegen/mutations.d.ts +0 -0
- /package/esm/{cli → core}/codegen/mutations.js +0 -0
- /package/esm/{cli → core}/codegen/orm/barrel.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/barrel.js +0 -0
- /package/esm/{cli → core}/codegen/orm/client-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/client.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/client.js +0 -0
- /package/esm/{cli → core}/codegen/orm/custom-ops-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/custom-ops-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/input-types-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/input-types-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/model-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/model-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/query-builder.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/query-builder.js +0 -0
- /package/esm/{cli → core}/codegen/orm/select-types.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/select-types.js +0 -0
- /package/esm/{cli → core}/codegen/queries.d.ts +0 -0
- /package/esm/{cli → core}/codegen/queries.js +0 -0
- /package/esm/{cli → core}/codegen/query-keys.js +0 -0
- /package/esm/{cli → core}/codegen/scalars.d.ts +0 -0
- /package/esm/{cli → core}/codegen/scalars.js +0 -0
- /package/esm/{cli → core}/codegen/schema-gql-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/schema-gql-ast.js +0 -0
- /package/esm/{cli → core}/codegen/schema-types-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/schema-types-generator.js +0 -0
- /package/esm/{cli → core}/codegen/type-resolver.d.ts +0 -0
- /package/esm/{cli → core}/codegen/type-resolver.js +0 -0
- /package/esm/{cli → core}/codegen/types.d.ts +0 -0
- /package/esm/{cli → core}/codegen/types.js +0 -0
- /package/esm/{cli → core}/codegen/utils.d.ts +0 -0
- /package/esm/{cli → core}/codegen/utils.js +0 -0
- /package/esm/{cli → core}/introspect/fetch-schema.d.ts +0 -0
- /package/esm/{cli → core}/introspect/index.d.ts +0 -0
- /package/esm/{cli → core}/introspect/index.js +0 -0
- /package/esm/{cli → core}/introspect/infer-tables.d.ts +0 -0
- /package/esm/{cli → core}/introspect/infer-tables.js +0 -0
- /package/esm/{cli → core}/introspect/schema-query.d.ts +0 -0
- /package/esm/{cli → core}/introspect/schema-query.js +0 -0
- /package/esm/{cli → core}/introspect/source/endpoint.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/endpoint.js +0 -0
- /package/esm/{cli → core}/introspect/source/file.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/file.js +0 -0
- /package/esm/{cli → core}/introspect/source/types.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/types.js +0 -0
- /package/esm/{cli → core}/introspect/transform-schema.d.ts +0 -0
- /package/esm/{cli → core}/introspect/transform-schema.js +0 -0
- /package/esm/{cli → core}/introspect/transform.d.ts +0 -0
- /package/esm/{cli → core}/introspect/transform.js +0 -0
- /package/esm/{cli → core}/watch/cache.d.ts +0 -0
- /package/esm/{cli → core}/watch/cache.js +0 -0
- /package/esm/{cli → core}/watch/debounce.d.ts +0 -0
- /package/esm/{cli → core}/watch/debounce.js +0 -0
- /package/esm/{cli → core}/watch/hash.d.ts +0 -0
- /package/esm/{cli → core}/watch/hash.js +0 -0
- /package/esm/{cli → core}/watch/index.d.ts +0 -0
- /package/esm/{cli → core}/watch/index.js +0 -0
- /package/esm/{cli → core}/watch/poller.d.ts +0 -0
- /package/esm/{cli → core}/watch/poller.js +0 -0
- /package/esm/{cli → core}/watch/types.js +0 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PGPM Module Schema Source
|
|
3
|
+
*
|
|
4
|
+
* Loads GraphQL schema from a PGPM module by:
|
|
5
|
+
* 1. Creating an ephemeral database
|
|
6
|
+
* 2. Deploying the module to the database
|
|
7
|
+
* 3. Introspecting the database with PostGraphile
|
|
8
|
+
* 4. Cleaning up the ephemeral database (unless keepDb is true)
|
|
9
|
+
*/
|
|
10
|
+
import { buildSchema, introspectionFromSchema } from 'graphql';
|
|
11
|
+
import { PgpmPackage } from '@pgpmjs/core';
|
|
12
|
+
import { createEphemeralDb } from 'pgsql-client';
|
|
13
|
+
import { deployPgpm } from 'pgsql-seed';
|
|
14
|
+
import { getPgPool } from 'pg-cache';
|
|
15
|
+
import { SchemaSourceError } from './types';
|
|
16
|
+
import { buildSchemaSDLFromDatabase } from '../../database';
|
|
17
|
+
import { resolveApiSchemas, validateServicesSchemas } from './api-schemas';
|
|
18
|
+
/**
|
|
19
|
+
* Type guard to check if options use direct module path
|
|
20
|
+
*/
|
|
21
|
+
export function isPgpmModulePathOptions(options) {
|
|
22
|
+
return 'pgpmModulePath' in options;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Type guard to check if options use workspace + module name
|
|
26
|
+
*/
|
|
27
|
+
export function isPgpmWorkspaceOptions(options) {
|
|
28
|
+
return 'pgpmWorkspacePath' in options && 'pgpmModuleName' in options;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Schema source that loads from a PGPM module
|
|
32
|
+
*
|
|
33
|
+
* Creates an ephemeral database, deploys the module, introspects the schema,
|
|
34
|
+
* and cleans up. Supports both direct module path and workspace + module name modes.
|
|
35
|
+
*/
|
|
36
|
+
export class PgpmModuleSchemaSource {
|
|
37
|
+
options;
|
|
38
|
+
ephemeralDb = null;
|
|
39
|
+
constructor(options) {
|
|
40
|
+
this.options = options;
|
|
41
|
+
}
|
|
42
|
+
async fetch() {
|
|
43
|
+
const keepDb = this.getKeepDb();
|
|
44
|
+
const apiNames = this.getApiNames();
|
|
45
|
+
// Resolve the module path
|
|
46
|
+
let modulePath;
|
|
47
|
+
try {
|
|
48
|
+
modulePath = this.resolveModulePath();
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
throw new SchemaSourceError(`Failed to resolve module path: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
52
|
+
}
|
|
53
|
+
// Validate the module exists
|
|
54
|
+
const pkg = new PgpmPackage(modulePath);
|
|
55
|
+
if (!pkg.isInModule()) {
|
|
56
|
+
throw new SchemaSourceError(`Not a valid PGPM module: ${modulePath}. Directory must contain pgpm.plan and .control files.`, this.describe());
|
|
57
|
+
}
|
|
58
|
+
// Create ephemeral database
|
|
59
|
+
try {
|
|
60
|
+
this.ephemeralDb = createEphemeralDb({
|
|
61
|
+
prefix: 'codegen_pgpm_',
|
|
62
|
+
verbose: false,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
throw new SchemaSourceError(`Failed to create ephemeral database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
67
|
+
}
|
|
68
|
+
const { config: dbConfig, teardown } = this.ephemeralDb;
|
|
69
|
+
try {
|
|
70
|
+
// Deploy the module to the ephemeral database
|
|
71
|
+
try {
|
|
72
|
+
await deployPgpm(dbConfig, modulePath, false);
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
throw new SchemaSourceError(`Failed to deploy PGPM module: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
76
|
+
}
|
|
77
|
+
// Resolve schemas - either from explicit schemas option or from apiNames (after deployment)
|
|
78
|
+
let schemas;
|
|
79
|
+
if (apiNames && apiNames.length > 0) {
|
|
80
|
+
// For PGPM mode, validate services schemas AFTER migration
|
|
81
|
+
const pool = getPgPool(dbConfig);
|
|
82
|
+
try {
|
|
83
|
+
const validation = await validateServicesSchemas(pool);
|
|
84
|
+
if (!validation.valid) {
|
|
85
|
+
throw new SchemaSourceError(validation.error, this.describe());
|
|
86
|
+
}
|
|
87
|
+
schemas = await resolveApiSchemas(pool, apiNames);
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
if (err instanceof SchemaSourceError)
|
|
91
|
+
throw err;
|
|
92
|
+
throw new SchemaSourceError(`Failed to resolve API schemas: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
schemas = this.getSchemas();
|
|
97
|
+
}
|
|
98
|
+
// Build SDL from the deployed database
|
|
99
|
+
let sdl;
|
|
100
|
+
try {
|
|
101
|
+
sdl = await buildSchemaSDLFromDatabase({
|
|
102
|
+
database: dbConfig.database,
|
|
103
|
+
schemas,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
throw new SchemaSourceError(`Failed to introspect database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
108
|
+
}
|
|
109
|
+
// Validate non-empty
|
|
110
|
+
if (!sdl.trim()) {
|
|
111
|
+
throw new SchemaSourceError('Database introspection returned empty schema', this.describe());
|
|
112
|
+
}
|
|
113
|
+
// Parse SDL to GraphQL schema
|
|
114
|
+
let schema;
|
|
115
|
+
try {
|
|
116
|
+
schema = buildSchema(sdl);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
throw new SchemaSourceError(`Invalid GraphQL SDL from database: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
120
|
+
}
|
|
121
|
+
// Convert to introspection format
|
|
122
|
+
let introspectionResult;
|
|
123
|
+
try {
|
|
124
|
+
introspectionResult = introspectionFromSchema(schema);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
throw new SchemaSourceError(`Failed to generate introspection: ${err instanceof Error ? err.message : 'Unknown error'}`, this.describe(), err instanceof Error ? err : undefined);
|
|
128
|
+
}
|
|
129
|
+
// Convert graphql-js introspection result to our mutable type
|
|
130
|
+
const introspection = JSON.parse(JSON.stringify(introspectionResult));
|
|
131
|
+
return { introspection };
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
// Clean up the ephemeral database
|
|
135
|
+
teardown({ keepDb });
|
|
136
|
+
if (keepDb) {
|
|
137
|
+
console.log(`[pgpm-module] Kept ephemeral database: ${dbConfig.database}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
describe() {
|
|
142
|
+
const apiNames = this.getApiNames();
|
|
143
|
+
if (isPgpmModulePathOptions(this.options)) {
|
|
144
|
+
if (apiNames && apiNames.length > 0) {
|
|
145
|
+
return `pgpm module: ${this.options.pgpmModulePath} (apiNames: ${apiNames.join(', ')})`;
|
|
146
|
+
}
|
|
147
|
+
const schemas = this.options.schemas ?? ['public'];
|
|
148
|
+
return `pgpm module: ${this.options.pgpmModulePath} (schemas: ${schemas.join(', ')})`;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
if (apiNames && apiNames.length > 0) {
|
|
152
|
+
return `pgpm workspace: ${this.options.pgpmWorkspacePath}, module: ${this.options.pgpmModuleName} (apiNames: ${apiNames.join(', ')})`;
|
|
153
|
+
}
|
|
154
|
+
const schemas = this.options.schemas ?? ['public'];
|
|
155
|
+
return `pgpm workspace: ${this.options.pgpmWorkspacePath}, module: ${this.options.pgpmModuleName} (schemas: ${schemas.join(', ')})`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
resolveModulePath() {
|
|
159
|
+
if (isPgpmModulePathOptions(this.options)) {
|
|
160
|
+
return this.options.pgpmModulePath;
|
|
161
|
+
}
|
|
162
|
+
// Workspace + module name mode
|
|
163
|
+
const { pgpmWorkspacePath, pgpmModuleName } = this.options;
|
|
164
|
+
const workspace = new PgpmPackage(pgpmWorkspacePath);
|
|
165
|
+
if (!workspace.workspacePath) {
|
|
166
|
+
throw new Error(`Not a valid PGPM workspace: ${pgpmWorkspacePath}`);
|
|
167
|
+
}
|
|
168
|
+
// Get the module from the workspace
|
|
169
|
+
const moduleProject = workspace.getModuleProject(pgpmModuleName);
|
|
170
|
+
const modulePath = moduleProject.getModulePath();
|
|
171
|
+
if (!modulePath) {
|
|
172
|
+
throw new Error(`Module "${pgpmModuleName}" not found in workspace`);
|
|
173
|
+
}
|
|
174
|
+
return modulePath;
|
|
175
|
+
}
|
|
176
|
+
getSchemas() {
|
|
177
|
+
if (isPgpmModulePathOptions(this.options)) {
|
|
178
|
+
return this.options.schemas ?? ['public'];
|
|
179
|
+
}
|
|
180
|
+
return this.options.schemas ?? ['public'];
|
|
181
|
+
}
|
|
182
|
+
getApiNames() {
|
|
183
|
+
if (isPgpmModulePathOptions(this.options)) {
|
|
184
|
+
return this.options.apiNames;
|
|
185
|
+
}
|
|
186
|
+
return this.options.apiNames;
|
|
187
|
+
}
|
|
188
|
+
getKeepDb() {
|
|
189
|
+
if (isPgpmModulePathOptions(this.options)) {
|
|
190
|
+
return this.options.keepDb ?? false;
|
|
191
|
+
}
|
|
192
|
+
return this.options.keepDb ?? false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { GeneratedFile } from '../codegen';
|
|
2
|
+
export type { GeneratedFile };
|
|
3
|
+
/**
|
|
4
|
+
* Result of writing files
|
|
5
|
+
*/
|
|
6
|
+
export interface WriteResult {
|
|
7
|
+
success: boolean;
|
|
8
|
+
filesWritten?: string[];
|
|
9
|
+
errors?: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Options for writing files
|
|
13
|
+
*/
|
|
14
|
+
export interface WriteOptions {
|
|
15
|
+
/** Show progress output (default: true) */
|
|
16
|
+
showProgress?: boolean;
|
|
17
|
+
/** Format files with oxfmt after writing (default: true) */
|
|
18
|
+
formatFiles?: boolean;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Write generated files to disk
|
|
22
|
+
*
|
|
23
|
+
* @param files - Array of files to write
|
|
24
|
+
* @param outputDir - Base output directory
|
|
25
|
+
* @param subdirs - Subdirectories to create
|
|
26
|
+
* @param options - Write options
|
|
27
|
+
*/
|
|
28
|
+
export declare function writeGeneratedFiles(files: GeneratedFile[], outputDir: string, subdirs: string[], options?: WriteOptions): Promise<WriteResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Format generated files using oxfmt
|
|
31
|
+
*
|
|
32
|
+
* Runs oxfmt on the output directory after all files are written.
|
|
33
|
+
* Uses the same formatting options as prettier: single quotes, trailing commas, 2-space tabs, semicolons.
|
|
34
|
+
*/
|
|
35
|
+
export declare function formatOutput(outputDir: string): {
|
|
36
|
+
success: boolean;
|
|
37
|
+
error?: string;
|
|
38
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File writing utilities
|
|
3
|
+
*
|
|
4
|
+
* Pure functions for writing generated files to disk and formatting them.
|
|
5
|
+
* These are core utilities that can be used programmatically or by the CLI.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
/**
|
|
11
|
+
* Write generated files to disk
|
|
12
|
+
*
|
|
13
|
+
* @param files - Array of files to write
|
|
14
|
+
* @param outputDir - Base output directory
|
|
15
|
+
* @param subdirs - Subdirectories to create
|
|
16
|
+
* @param options - Write options
|
|
17
|
+
*/
|
|
18
|
+
export async function writeGeneratedFiles(files, outputDir, subdirs, options = {}) {
|
|
19
|
+
const { showProgress = true, formatFiles = true } = options;
|
|
20
|
+
const errors = [];
|
|
21
|
+
const written = [];
|
|
22
|
+
const total = files.length;
|
|
23
|
+
const isTTY = process.stdout.isTTY;
|
|
24
|
+
// Ensure output directory exists
|
|
25
|
+
try {
|
|
26
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
30
|
+
return {
|
|
31
|
+
success: false,
|
|
32
|
+
errors: [`Failed to create output directory: ${message}`],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// Create subdirectories
|
|
36
|
+
for (const subdir of subdirs) {
|
|
37
|
+
const subdirPath = path.join(outputDir, subdir);
|
|
38
|
+
try {
|
|
39
|
+
fs.mkdirSync(subdirPath, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
43
|
+
errors.push(`Failed to create directory ${subdirPath}: ${message}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (errors.length > 0) {
|
|
47
|
+
return { success: false, errors };
|
|
48
|
+
}
|
|
49
|
+
for (let i = 0; i < files.length; i++) {
|
|
50
|
+
const file = files[i];
|
|
51
|
+
const filePath = path.join(outputDir, file.path);
|
|
52
|
+
// Show progress
|
|
53
|
+
if (showProgress) {
|
|
54
|
+
const progress = Math.round(((i + 1) / total) * 100);
|
|
55
|
+
if (isTTY) {
|
|
56
|
+
process.stdout.write(`\rWriting files: ${i + 1}/${total} (${progress}%)`);
|
|
57
|
+
}
|
|
58
|
+
else if (i % 100 === 0 || i === total - 1) {
|
|
59
|
+
// Non-TTY: periodic updates for CI/CD
|
|
60
|
+
console.log(`Writing files: ${i + 1}/${total}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Ensure parent directory exists
|
|
64
|
+
const parentDir = path.dirname(filePath);
|
|
65
|
+
try {
|
|
66
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Ignore if already exists
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
fs.writeFileSync(filePath, file.content, 'utf-8');
|
|
73
|
+
written.push(filePath);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
77
|
+
errors.push(`Failed to write ${filePath}: ${message}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Clear progress line
|
|
81
|
+
if (showProgress && isTTY) {
|
|
82
|
+
process.stdout.write('\r' + ' '.repeat(40) + '\r');
|
|
83
|
+
}
|
|
84
|
+
// Format all generated files with oxfmt
|
|
85
|
+
if (formatFiles && errors.length === 0) {
|
|
86
|
+
if (showProgress) {
|
|
87
|
+
console.log('Formatting generated files...');
|
|
88
|
+
}
|
|
89
|
+
const formatResult = formatOutput(outputDir);
|
|
90
|
+
if (!formatResult.success && showProgress) {
|
|
91
|
+
console.warn('Warning: Failed to format generated files:', formatResult.error);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
success: errors.length === 0,
|
|
96
|
+
filesWritten: written,
|
|
97
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Format generated files using oxfmt
|
|
102
|
+
*
|
|
103
|
+
* Runs oxfmt on the output directory after all files are written.
|
|
104
|
+
* Uses the same formatting options as prettier: single quotes, trailing commas, 2-space tabs, semicolons.
|
|
105
|
+
*/
|
|
106
|
+
export function formatOutput(outputDir) {
|
|
107
|
+
const absoluteOutputDir = path.resolve(outputDir);
|
|
108
|
+
try {
|
|
109
|
+
execSync(`npx oxfmt --write "${absoluteOutputDir}"`, {
|
|
110
|
+
stdio: 'pipe',
|
|
111
|
+
encoding: 'utf-8',
|
|
112
|
+
});
|
|
113
|
+
return { success: true };
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
117
|
+
return { success: false, error: message };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -8,18 +8,20 @@
|
|
|
8
8
|
* - Operation transformation
|
|
9
9
|
* - Filtering
|
|
10
10
|
*/
|
|
11
|
-
import type {
|
|
11
|
+
import type { GraphQLSDKConfigTarget } from '../../types/config';
|
|
12
12
|
import type { CleanTable, CleanOperation, TypeRegistry } from '../../types/schema';
|
|
13
13
|
import type { SchemaSource } from '../introspect/source';
|
|
14
|
+
export type { SchemaSource } from '../introspect/source';
|
|
15
|
+
export { createSchemaSource, validateSourceOptions } from '../introspect/source';
|
|
14
16
|
export interface CodegenPipelineOptions {
|
|
15
17
|
/**
|
|
16
18
|
* Schema source (endpoint or file)
|
|
17
19
|
*/
|
|
18
20
|
source: SchemaSource;
|
|
19
21
|
/**
|
|
20
|
-
*
|
|
22
|
+
* Configuration
|
|
21
23
|
*/
|
|
22
|
-
config:
|
|
24
|
+
config: GraphQLSDKConfigTarget;
|
|
23
25
|
/**
|
|
24
26
|
* Enable verbose logging
|
|
25
27
|
*/
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { inferTablesFromIntrospection } from '../introspect/infer-tables';
|
|
2
2
|
import { filterTables } from '../introspect/transform';
|
|
3
3
|
import { transformSchemaToOperations, filterOperations, getTableOperationNames, getCustomOperations, } from '../introspect/transform-schema';
|
|
4
|
+
export { createSchemaSource, validateSourceOptions } from '../introspect/source';
|
|
4
5
|
// ============================================================================
|
|
5
6
|
// Main Pipeline
|
|
6
7
|
// ============================================================================
|
|
@@ -3,10 +3,28 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Coordinates schema polling, change detection, and code regeneration
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type { GraphQLSDKConfigTarget } from '../../types/config';
|
|
7
7
|
import type { GeneratorType } from './types';
|
|
8
|
+
export interface GenerateFunction {
|
|
9
|
+
(options: {
|
|
10
|
+
config?: string;
|
|
11
|
+
target?: string;
|
|
12
|
+
endpoint?: string;
|
|
13
|
+
output?: string;
|
|
14
|
+
authorization?: string;
|
|
15
|
+
verbose?: boolean;
|
|
16
|
+
skipCustomOperations?: boolean;
|
|
17
|
+
}): Promise<GenerateResult>;
|
|
18
|
+
}
|
|
19
|
+
export interface GenerateResult {
|
|
20
|
+
success: boolean;
|
|
21
|
+
message: string;
|
|
22
|
+
tables?: string[];
|
|
23
|
+
filesWritten?: string[];
|
|
24
|
+
errors?: string[];
|
|
25
|
+
}
|
|
8
26
|
export interface WatchOrchestratorOptions {
|
|
9
|
-
config:
|
|
27
|
+
config: GraphQLSDKConfigTarget;
|
|
10
28
|
generatorType: GeneratorType;
|
|
11
29
|
verbose: boolean;
|
|
12
30
|
authorization?: string;
|
|
@@ -14,10 +32,14 @@ export interface WatchOrchestratorOptions {
|
|
|
14
32
|
configPath?: string;
|
|
15
33
|
/** Target name for multi-target configs */
|
|
16
34
|
target?: string;
|
|
17
|
-
/** Override output directory
|
|
35
|
+
/** Override output directory */
|
|
18
36
|
outputDir?: string;
|
|
19
37
|
/** Skip custom operations flag */
|
|
20
38
|
skipCustomOperations?: boolean;
|
|
39
|
+
/** Generator function for React Query SDK */
|
|
40
|
+
generateReactQuery: GenerateFunction;
|
|
41
|
+
/** Generator function for ORM client */
|
|
42
|
+
generateOrm: GenerateFunction;
|
|
21
43
|
}
|
|
22
44
|
export interface WatchStatus {
|
|
23
45
|
isRunning: boolean;
|
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { SchemaPoller } from './poller';
|
|
7
7
|
import { debounce } from './debounce';
|
|
8
|
-
import { generateReactQuery } from '../commands/generate';
|
|
9
|
-
import { generateOrm, } from '../commands/generate-orm';
|
|
10
8
|
/**
|
|
11
9
|
* Main watch orchestrator class
|
|
12
10
|
*/
|
|
@@ -131,29 +129,31 @@ export class WatchOrchestrator {
|
|
|
131
129
|
}
|
|
132
130
|
this.log('Regenerating...');
|
|
133
131
|
try {
|
|
134
|
-
let
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
target: this.options.target,
|
|
150
|
-
endpoint: this.options.config.endpoint,
|
|
151
|
-
output: this.options.outputDir ?? this.options.config.orm.output,
|
|
152
|
-
authorization: this.options.authorization,
|
|
153
|
-
verbose: this.watchOptions.verbose,
|
|
154
|
-
skipCustomOperations: this.options.skipCustomOperations,
|
|
155
|
-
});
|
|
132
|
+
let generateFn;
|
|
133
|
+
let outputDir;
|
|
134
|
+
switch (this.options.generatorType) {
|
|
135
|
+
case 'react-query':
|
|
136
|
+
generateFn = this.options.generateReactQuery;
|
|
137
|
+
// React Query hooks go to {output}/hooks
|
|
138
|
+
outputDir = this.options.outputDir ?? `${this.options.config.output}/hooks`;
|
|
139
|
+
break;
|
|
140
|
+
case 'orm':
|
|
141
|
+
generateFn = this.options.generateOrm;
|
|
142
|
+
// ORM client goes to {output}/orm
|
|
143
|
+
outputDir = this.options.outputDir ?? `${this.options.config.output}/orm`;
|
|
144
|
+
break;
|
|
145
|
+
default:
|
|
146
|
+
throw new Error(`Unknown generator type: ${this.options.generatorType}`);
|
|
156
147
|
}
|
|
148
|
+
const result = await generateFn({
|
|
149
|
+
config: this.options.configPath,
|
|
150
|
+
target: this.options.target,
|
|
151
|
+
endpoint: this.options.config.endpoint,
|
|
152
|
+
output: outputDir,
|
|
153
|
+
authorization: this.options.authorization,
|
|
154
|
+
verbose: this.watchOptions.verbose,
|
|
155
|
+
skipCustomOperations: this.options.skipCustomOperations,
|
|
156
|
+
});
|
|
157
157
|
const duration = Date.now() - startTime;
|
|
158
158
|
if (result.success) {
|
|
159
159
|
this.status.regenerateCount++;
|
|
@@ -193,9 +193,17 @@ export class WatchOrchestrator {
|
|
|
193
193
|
process.stdout.write('\x1B[2J\x1B[0f');
|
|
194
194
|
}
|
|
195
195
|
logHeader() {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
196
|
+
let generatorName;
|
|
197
|
+
switch (this.options.generatorType) {
|
|
198
|
+
case 'react-query':
|
|
199
|
+
generatorName = 'React Query hooks';
|
|
200
|
+
break;
|
|
201
|
+
case 'orm':
|
|
202
|
+
generatorName = 'ORM client';
|
|
203
|
+
break;
|
|
204
|
+
default:
|
|
205
|
+
throw new Error(`Unknown generator type: ${this.options.generatorType}`);
|
|
206
|
+
}
|
|
199
207
|
console.log(`\n${'─'.repeat(50)}`);
|
|
200
208
|
console.log(`graphql-codegen watch mode (${generatorName})`);
|
|
201
209
|
console.log(`Endpoint: ${this.options.config.endpoint}`);
|
package/esm/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @constructive-io/graphql-codegen
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* GraphQL SDK generator for Constructive databases.
|
|
5
5
|
* Introspects via _meta query and generates typed queries, mutations,
|
|
6
6
|
* and React Query v5 hooks.
|
|
7
7
|
*/
|
|
@@ -10,5 +10,10 @@ export * from './core';
|
|
|
10
10
|
export * from './generators';
|
|
11
11
|
export * from './client';
|
|
12
12
|
export { defineConfig } from './types/config';
|
|
13
|
-
export {
|
|
14
|
-
export type { GenerateOptions, GenerateResult
|
|
13
|
+
export { generate } from './core/generate';
|
|
14
|
+
export type { GenerateOptions, GenerateResult } from './core/generate';
|
|
15
|
+
export { findConfigFile, loadConfigFile } from './core/config';
|
|
16
|
+
export { codegenQuestions, splitCommas, printResult } from './cli/shared';
|
|
17
|
+
export type { CodegenAnswers } from './cli/shared';
|
|
18
|
+
export { buildSchemaFromDatabase, buildSchemaSDLFromDatabase, } from './core/database';
|
|
19
|
+
export type { BuildSchemaFromDatabaseOptions, BuildSchemaFromDatabaseResult, } from './core/database';
|
package/esm/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @constructive-io/graphql-codegen
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* GraphQL SDK generator for Constructive databases.
|
|
5
5
|
* Introspects via _meta query and generates typed queries, mutations,
|
|
6
6
|
* and React Query v5 hooks.
|
|
7
7
|
*/
|
|
@@ -15,5 +15,11 @@ export * from './generators';
|
|
|
15
15
|
export * from './client';
|
|
16
16
|
// Config definition helper
|
|
17
17
|
export { defineConfig } from './types/config';
|
|
18
|
-
//
|
|
19
|
-
export {
|
|
18
|
+
// Main generate function (orchestrates the entire pipeline)
|
|
19
|
+
export { generate } from './core/generate';
|
|
20
|
+
// Config utilities
|
|
21
|
+
export { findConfigFile, loadConfigFile } from './core/config';
|
|
22
|
+
// CLI shared utilities (for packages/cli to import)
|
|
23
|
+
export { codegenQuestions, splitCommas, printResult } from './cli/shared';
|
|
24
|
+
// Database schema utilities (re-exported from core for convenience)
|
|
25
|
+
export { buildSchemaFromDatabase, buildSchemaSDLFromDatabase, } from './core/database';
|