@constructive-io/graphql-codegen 2.22.1 → 2.23.0

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.
Files changed (95) hide show
  1. package/cli/codegen/barrel.d.ts +5 -1
  2. package/cli/codegen/barrel.js +13 -11
  3. package/cli/codegen/index.d.ts +3 -3
  4. package/cli/codegen/index.js +15 -9
  5. package/cli/codegen/orm/client-generator.js +3 -2
  6. package/cli/codegen/orm/custom-ops-generator.js +17 -4
  7. package/cli/codegen/orm/input-types-generator.js +129 -18
  8. package/cli/codegen/orm/model-generator.js +2 -1
  9. package/cli/codegen/orm/query-builder.d.ts +1 -1
  10. package/cli/codegen/orm/query-builder.js +2 -2
  11. package/cli/codegen/schema-types-generator.js +5 -5
  12. package/cli/codegen/utils.d.ts +6 -1
  13. package/cli/codegen/utils.js +23 -8
  14. package/cli/commands/generate-orm.d.ts +5 -3
  15. package/cli/commands/generate-orm.js +65 -84
  16. package/cli/commands/generate.d.ts +2 -0
  17. package/cli/commands/generate.js +66 -87
  18. package/cli/commands/shared.d.ts +74 -0
  19. package/cli/commands/shared.js +88 -0
  20. package/cli/index.js +75 -45
  21. package/cli/introspect/index.d.ts +8 -5
  22. package/cli/introspect/index.js +19 -7
  23. package/cli/introspect/infer-tables.d.ts +51 -0
  24. package/cli/introspect/infer-tables.js +550 -0
  25. package/cli/introspect/pluralize.d.ts +30 -0
  26. package/cli/introspect/pluralize.js +124 -0
  27. package/cli/introspect/source/endpoint.d.ts +34 -0
  28. package/cli/introspect/source/endpoint.js +35 -0
  29. package/cli/introspect/source/file.d.ts +20 -0
  30. package/cli/introspect/source/file.js +103 -0
  31. package/cli/introspect/source/index.d.ts +48 -0
  32. package/cli/introspect/source/index.js +72 -0
  33. package/cli/introspect/source/types.d.ts +58 -0
  34. package/cli/introspect/source/types.js +27 -0
  35. package/cli/introspect/transform.d.ts +5 -6
  36. package/cli/introspect/transform.js +0 -173
  37. package/cli/watch/cache.d.ts +3 -4
  38. package/cli/watch/cache.js +6 -10
  39. package/cli/watch/poller.d.ts +1 -2
  40. package/cli/watch/poller.js +27 -45
  41. package/cli/watch/types.d.ts +0 -3
  42. package/esm/cli/codegen/barrel.d.ts +5 -1
  43. package/esm/cli/codegen/barrel.js +13 -11
  44. package/esm/cli/codegen/index.d.ts +3 -3
  45. package/esm/cli/codegen/index.js +18 -12
  46. package/esm/cli/codegen/orm/client-generator.js +3 -2
  47. package/esm/cli/codegen/orm/custom-ops-generator.js +18 -5
  48. package/esm/cli/codegen/orm/input-types-generator.js +130 -19
  49. package/esm/cli/codegen/orm/model-generator.js +3 -2
  50. package/esm/cli/codegen/orm/query-builder.d.ts +1 -1
  51. package/esm/cli/codegen/orm/query-builder.js +2 -2
  52. package/esm/cli/codegen/schema-types-generator.js +6 -6
  53. package/esm/cli/codegen/utils.d.ts +6 -1
  54. package/esm/cli/codegen/utils.js +22 -8
  55. package/esm/cli/commands/generate-orm.d.ts +5 -3
  56. package/esm/cli/commands/generate-orm.js +65 -84
  57. package/esm/cli/commands/generate.d.ts +2 -0
  58. package/esm/cli/commands/generate.js +66 -87
  59. package/esm/cli/commands/shared.d.ts +74 -0
  60. package/esm/cli/commands/shared.js +84 -0
  61. package/esm/cli/index.js +76 -46
  62. package/esm/cli/introspect/index.d.ts +8 -5
  63. package/esm/cli/introspect/index.js +10 -3
  64. package/esm/cli/introspect/infer-tables.d.ts +51 -0
  65. package/esm/cli/introspect/infer-tables.js +547 -0
  66. package/esm/cli/introspect/pluralize.d.ts +30 -0
  67. package/esm/cli/introspect/pluralize.js +83 -0
  68. package/esm/cli/introspect/source/endpoint.d.ts +34 -0
  69. package/esm/cli/introspect/source/endpoint.js +31 -0
  70. package/esm/cli/introspect/source/file.d.ts +20 -0
  71. package/esm/cli/introspect/source/file.js +66 -0
  72. package/esm/cli/introspect/source/index.d.ts +48 -0
  73. package/esm/cli/introspect/source/index.js +54 -0
  74. package/esm/cli/introspect/source/types.d.ts +58 -0
  75. package/esm/cli/introspect/source/types.js +23 -0
  76. package/esm/cli/introspect/transform.d.ts +5 -6
  77. package/esm/cli/introspect/transform.js +0 -172
  78. package/esm/cli/watch/cache.d.ts +3 -4
  79. package/esm/cli/watch/cache.js +7 -11
  80. package/esm/cli/watch/poller.d.ts +1 -2
  81. package/esm/cli/watch/poller.js +28 -46
  82. package/esm/cli/watch/types.d.ts +0 -3
  83. package/esm/types/config.d.ts +21 -5
  84. package/esm/types/config.js +2 -1
  85. package/package.json +4 -2
  86. package/types/config.d.ts +21 -5
  87. package/types/config.js +2 -1
  88. package/cli/introspect/fetch-meta.d.ts +0 -31
  89. package/cli/introspect/fetch-meta.js +0 -108
  90. package/cli/introspect/meta-query.d.ts +0 -111
  91. package/cli/introspect/meta-query.js +0 -191
  92. package/esm/cli/introspect/fetch-meta.d.ts +0 -31
  93. package/esm/cli/introspect/fetch-meta.js +0 -104
  94. package/esm/cli/introspect/meta-query.d.ts +0 -111
  95. package/esm/cli/introspect/meta-query.js +0 -188
@@ -19,7 +19,11 @@ export declare function generateMutationsBarrel(tables: CleanTable[]): string;
19
19
  * @param tables - The tables to include in the SDK
20
20
  * @param hasSchemaTypes - Whether schema-types.ts was generated
21
21
  */
22
- export declare function generateMainBarrel(tables: CleanTable[], hasSchemaTypes?: boolean): string;
22
+ export interface MainBarrelOptions {
23
+ hasSchemaTypes?: boolean;
24
+ hasMutations?: boolean;
25
+ }
26
+ export declare function generateMainBarrel(tables: CleanTable[], options?: MainBarrelOptions | boolean): string;
23
27
  /**
24
28
  * Generate queries barrel including custom query operations
25
29
  */
@@ -46,18 +46,23 @@ function generateMutationsBarrel(tables) {
46
46
  }
47
47
  return lines.join('\n') + '\n';
48
48
  }
49
- /**
50
- * Generate the main index.ts barrel file
51
- *
52
- * @param tables - The tables to include in the SDK
53
- * @param hasSchemaTypes - Whether schema-types.ts was generated
54
- */
55
- function generateMainBarrel(tables, hasSchemaTypes = false) {
49
+ function generateMainBarrel(tables, options = {}) {
50
+ // Support legacy signature where second arg was just hasSchemaTypes boolean
51
+ const opts = typeof options === 'boolean'
52
+ ? { hasSchemaTypes: options, hasMutations: true }
53
+ : options;
54
+ const { hasSchemaTypes = false, hasMutations = true } = opts;
56
55
  const tableNames = tables.map((t) => t.name).join(', ');
57
56
  const schemaTypesExport = hasSchemaTypes
58
57
  ? `
59
58
  // Schema types (input, payload, enum types)
60
59
  export * from './schema-types';
60
+ `
61
+ : '';
62
+ const mutationsExport = hasMutations
63
+ ? `
64
+ // Mutation hooks
65
+ export * from './mutations';
61
66
  `
62
67
  : '';
63
68
  return `/**
@@ -98,10 +103,7 @@ export * from './types';
98
103
  ${schemaTypesExport}
99
104
  // Query hooks
100
105
  export * from './queries';
101
-
102
- // Mutation hooks
103
- export * from './mutations';
104
- `;
106
+ ${mutationsExport}`;
105
107
  }
106
108
  // ============================================================================
107
109
  // Custom operation barrels (includes both table and custom hooks)
@@ -64,8 +64,8 @@ export declare function generateAllFiles(tables: CleanTable[], config: ResolvedC
64
64
  export declare function generate(options: GenerateOptions): GenerateResult;
65
65
  export { generateClientFile } from './client';
66
66
  export { generateTypesFile } from './types';
67
- export { generateAllQueryHooks, generateListQueryHook, generateSingleQueryHook } from './queries';
67
+ export { generateAllQueryHooks, generateListQueryHook, generateSingleQueryHook, } from './queries';
68
68
  export { generateAllMutationHooks, generateCreateMutationHook, generateUpdateMutationHook, generateDeleteMutationHook, } from './mutations';
69
- export { generateAllCustomQueryHooks, generateCustomQueryHook } from './custom-queries';
70
- export { generateAllCustomMutationHooks, generateCustomMutationHook } from './custom-mutations';
69
+ export { generateAllCustomQueryHooks, generateCustomQueryHook, } from './custom-queries';
70
+ export { generateAllCustomMutationHooks, generateCustomMutationHook, } from './custom-mutations';
71
71
  export { generateQueriesBarrel, generateMutationsBarrel, generateMainBarrel, generateCustomQueriesBarrel, generateCustomMutationsBarrel, } from './barrel';
@@ -60,7 +60,9 @@ function generate(options) {
60
60
  // 3. Generate types.ts (can now import enums from schema-types)
61
61
  files.push({
62
62
  path: 'types.ts',
63
- content: (0, types_1.generateTypesFile)(tables, { enumsFromSchemaTypes: generatedEnumNames }),
63
+ content: (0, types_1.generateTypesFile)(tables, {
64
+ enumsFromSchemaTypes: generatedEnumNames,
65
+ }),
64
66
  });
65
67
  // 4. Generate table-based query hooks (queries/*.ts)
66
68
  const queryHooks = (0, queries_1.generateAllQueryHooks)(tables, { reactQueryEnabled });
@@ -124,17 +126,21 @@ function generate(options) {
124
126
  });
125
127
  }
126
128
  }
127
- // 8. Generate mutations/index.ts barrel (includes both table and custom mutations)
128
- files.push({
129
- path: 'mutations/index.ts',
130
- content: customMutationHooks.length > 0
131
- ? (0, barrel_1.generateCustomMutationsBarrel)(tables, customMutationHooks.map((h) => h.operationName))
132
- : (0, barrel_1.generateMutationsBarrel)(tables),
133
- });
129
+ // 8. Generate mutations/index.ts barrel (only if React Query is enabled)
130
+ // When reactQuery is disabled, no mutation hooks are generated, so skip the barrel
131
+ const hasMutations = mutationHooks.length > 0 || customMutationHooks.length > 0;
132
+ if (hasMutations) {
133
+ files.push({
134
+ path: 'mutations/index.ts',
135
+ content: customMutationHooks.length > 0
136
+ ? (0, barrel_1.generateCustomMutationsBarrel)(tables, customMutationHooks.map((h) => h.operationName))
137
+ : (0, barrel_1.generateMutationsBarrel)(tables),
138
+ });
139
+ }
134
140
  // 9. Generate main index.ts barrel (with schema-types if present)
135
141
  files.push({
136
142
  path: 'index.ts',
137
- content: (0, barrel_1.generateMainBarrel)(tables, hasSchemaTypes),
143
+ content: (0, barrel_1.generateMainBarrel)(tables, { hasSchemaTypes, hasMutations }),
138
144
  });
139
145
  return {
140
146
  files,
@@ -282,7 +282,8 @@ export function buildFindManyDocument<TSelect, TWhere>(
282
282
  before?: string;
283
283
  offset?: number;
284
284
  },
285
- filterTypeName: string
285
+ filterTypeName: string,
286
+ orderByTypeName: string
286
287
  ): { document: string; variables: Record<string, unknown> } {
287
288
  const selections = select ? buildSelections(select) : 'id';
288
289
 
@@ -296,7 +297,7 @@ export function buildFindManyDocument<TSelect, TWhere>(
296
297
  variables.where = args.where;
297
298
  }
298
299
  if (args.orderBy?.length) {
299
- varDefs.push(\`$orderBy: [\${operationName}sOrderBy!]\`);
300
+ varDefs.push(\`$orderBy: [\${orderByTypeName}!]\`);
300
301
  queryArgs.push('orderBy: $orderBy');
301
302
  variables.orderBy = args.orderBy;
302
303
  }
@@ -8,13 +8,18 @@ const type_resolver_1 = require("../type-resolver");
8
8
  const scalars_1 = require("../scalars");
9
9
  /**
10
10
  * Collect all input type names used by operations
11
+ * Includes Input, Filter, OrderBy, and Condition types
11
12
  */
12
13
  function collectInputTypeNamesFromOps(operations) {
13
14
  const inputTypes = new Set();
14
15
  for (const op of operations) {
15
16
  for (const arg of op.args) {
16
17
  const baseName = (0, type_resolver_1.getTypeBaseName)(arg.type);
17
- if (baseName && (baseName.endsWith('Input') || baseName.endsWith('Filter'))) {
18
+ if (baseName &&
19
+ (baseName.endsWith('Input') ||
20
+ baseName.endsWith('Filter') ||
21
+ baseName.endsWith('OrderBy') ||
22
+ baseName.endsWith('Condition'))) {
18
23
  inputTypes.add(baseName);
19
24
  }
20
25
  }
@@ -22,7 +27,11 @@ function collectInputTypeNamesFromOps(operations) {
22
27
  return Array.from(inputTypes);
23
28
  }
24
29
  // Types that don't need Select types
25
- const NON_SELECT_TYPES = new Set([...scalars_1.SCALAR_NAMES, 'Query', 'Mutation']);
30
+ const NON_SELECT_TYPES = new Set([
31
+ ...scalars_1.SCALAR_NAMES,
32
+ 'Query',
33
+ 'Mutation',
34
+ ]);
26
35
  /**
27
36
  * Collect all payload/return type names from operations (for Select types)
28
37
  * Filters out scalar types
@@ -68,7 +77,9 @@ function generateCustomQueryOpsFile(operations) {
68
77
  // Generate Select type names for payloads
69
78
  const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`);
70
79
  // Combine all type imports
71
- const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])];
80
+ const allTypeImports = [
81
+ ...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames]),
82
+ ];
72
83
  // Add file header
73
84
  sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)('Custom query operations') + '\n\n');
74
85
  // Add imports
@@ -201,7 +212,9 @@ function generateCustomMutationOpsFile(operations) {
201
212
  // Generate Select type names for payloads
202
213
  const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`);
203
214
  // Combine all type imports
204
- const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])];
215
+ const allTypeImports = [
216
+ ...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames]),
217
+ ];
205
218
  // Add file header
206
219
  sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)('Custom mutation operations') + '\n\n');
207
220
  // Add imports
@@ -5,13 +5,19 @@ exports.collectPayloadTypeNames = collectPayloadTypeNames;
5
5
  exports.generateInputTypesFile = generateInputTypesFile;
6
6
  const ts_ast_1 = require("../ts-ast");
7
7
  const utils_1 = require("../utils");
8
+ const pluralize_1 = require("../../introspect/pluralize");
8
9
  const type_resolver_1 = require("../type-resolver");
9
10
  const scalars_1 = require("../scalars");
10
11
  // ============================================================================
11
12
  // Constants
12
13
  // ============================================================================
13
14
  /** Fields excluded from Create/Update inputs (auto-generated or system fields) */
14
- const EXCLUDED_MUTATION_FIELDS = ['id', 'createdAt', 'updatedAt', 'nodeId'];
15
+ const EXCLUDED_MUTATION_FIELDS = [
16
+ 'id',
17
+ 'createdAt',
18
+ 'updatedAt',
19
+ 'nodeId',
20
+ ];
15
21
  // ============================================================================
16
22
  // Type Conversion Utilities
17
23
  // ============================================================================
@@ -58,18 +64,58 @@ function isRequired(typeRef) {
58
64
  }
59
65
  /** Configuration for all scalar filter types - matches PostGraphile's generated filters */
60
66
  const SCALAR_FILTER_CONFIGS = [
61
- { name: 'StringFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison', 'string'] },
62
- { name: 'IntFilter', tsType: 'number', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
63
- { name: 'FloatFilter', tsType: 'number', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
67
+ {
68
+ name: 'StringFilter',
69
+ tsType: 'string',
70
+ operators: ['equality', 'distinct', 'inArray', 'comparison', 'string'],
71
+ },
72
+ {
73
+ name: 'IntFilter',
74
+ tsType: 'number',
75
+ operators: ['equality', 'distinct', 'inArray', 'comparison'],
76
+ },
77
+ {
78
+ name: 'FloatFilter',
79
+ tsType: 'number',
80
+ operators: ['equality', 'distinct', 'inArray', 'comparison'],
81
+ },
64
82
  { name: 'BooleanFilter', tsType: 'boolean', operators: ['equality'] },
65
- { name: 'UUIDFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray'] },
66
- { name: 'DatetimeFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
67
- { name: 'DateFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
68
- { name: 'JSONFilter', tsType: 'Record<string, unknown>', operators: ['equality', 'distinct', 'json'] },
69
- { name: 'BigIntFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
70
- { name: 'BigFloatFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
83
+ {
84
+ name: 'UUIDFilter',
85
+ tsType: 'string',
86
+ operators: ['equality', 'distinct', 'inArray'],
87
+ },
88
+ {
89
+ name: 'DatetimeFilter',
90
+ tsType: 'string',
91
+ operators: ['equality', 'distinct', 'inArray', 'comparison'],
92
+ },
93
+ {
94
+ name: 'DateFilter',
95
+ tsType: 'string',
96
+ operators: ['equality', 'distinct', 'inArray', 'comparison'],
97
+ },
98
+ {
99
+ name: 'JSONFilter',
100
+ tsType: 'Record<string, unknown>',
101
+ operators: ['equality', 'distinct', 'json'],
102
+ },
103
+ {
104
+ name: 'BigIntFilter',
105
+ tsType: 'string',
106
+ operators: ['equality', 'distinct', 'inArray', 'comparison'],
107
+ },
108
+ {
109
+ name: 'BigFloatFilter',
110
+ tsType: 'string',
111
+ operators: ['equality', 'distinct', 'inArray', 'comparison'],
112
+ },
71
113
  { name: 'BitStringFilter', tsType: 'string', operators: ['equality'] },
72
- { name: 'InternetAddressFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'] },
114
+ {
115
+ name: 'InternetAddressFilter',
116
+ tsType: 'string',
117
+ operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'],
118
+ },
73
119
  { name: 'FullTextFilter', tsType: 'string', operators: ['fulltext'] },
74
120
  ];
75
121
  /**
@@ -229,7 +275,15 @@ function getRelatedTypeName(tableName, tableByName) {
229
275
  }
230
276
  function getRelatedOrderByName(tableName, tableByName) {
231
277
  const relatedTable = tableByName.get(tableName);
232
- return relatedTable ? (0, utils_1.getOrderByTypeName)(relatedTable) : `${tableName}sOrderBy`;
278
+ if (relatedTable) {
279
+ return (0, utils_1.getOrderByTypeName)(relatedTable);
280
+ }
281
+ // For ManyToMany connection types, don't pluralize - just append OrderBy
282
+ // These types already have a fixed suffix pattern like "UserUsersByFooManyToMany"
283
+ if (tableName.endsWith('ManyToMany')) {
284
+ return `${tableName}OrderBy`;
285
+ }
286
+ return `${(0, pluralize_1.pluralize)(tableName)}OrderBy`;
233
287
  }
234
288
  function getRelatedFilterName(tableName, tableByName) {
235
289
  const relatedTable = tableByName.get(tableName);
@@ -410,6 +464,39 @@ function addTableFilterTypes(sourceFile, tables) {
410
464
  }
411
465
  }
412
466
  // ============================================================================
467
+ // Condition Types Generator (AST-based)
468
+ // ============================================================================
469
+ /**
470
+ * Build properties for a table condition interface
471
+ * Condition types are simpler than Filter types - they use direct value equality
472
+ */
473
+ function buildTableConditionProperties(table) {
474
+ const properties = [];
475
+ for (const field of table.fields) {
476
+ const fieldType = typeof field.type === 'string' ? field.type : field.type.gqlType;
477
+ if ((0, utils_1.isRelationField)(field.name, table))
478
+ continue;
479
+ // Condition types use the raw scalar type (nullable)
480
+ const tsType = (0, scalars_1.scalarToTsType)(fieldType, { unknownScalar: 'unknown' });
481
+ properties.push({
482
+ name: field.name,
483
+ type: `${tsType} | null`,
484
+ optional: true,
485
+ });
486
+ }
487
+ return properties;
488
+ }
489
+ /**
490
+ * Add table condition types
491
+ */
492
+ function addTableConditionTypes(sourceFile, tables) {
493
+ (0, ts_ast_1.addSectionComment)(sourceFile, 'Table Condition Types');
494
+ for (const table of tables) {
495
+ const conditionName = (0, utils_1.getConditionTypeName)(table);
496
+ sourceFile.addInterface((0, ts_ast_1.createInterface)(conditionName, buildTableConditionProperties(table)));
497
+ }
498
+ }
499
+ // ============================================================================
413
500
  // OrderBy Types Generator (AST-based)
414
501
  // ============================================================================
415
502
  /**
@@ -493,7 +580,11 @@ function buildPatchProperties(table) {
493
580
  continue;
494
581
  const fieldType = typeof field.type === 'string' ? field.type : field.type.gqlType;
495
582
  const tsType = scalarToInputTs(fieldType);
496
- properties.push({ name: field.name, type: `${tsType} | null`, optional: true });
583
+ properties.push({
584
+ name: field.name,
585
+ type: `${tsType} | null`,
586
+ optional: true,
587
+ });
497
588
  }
498
589
  return properties;
499
590
  }
@@ -607,7 +698,9 @@ function addCustomInputTypes(sourceFile, typeRegistry, usedInputTypes, tableCrud
607
698
  properties.push({ name: field.name, type: tsType, optional });
608
699
  // Follow nested Input types
609
700
  const baseType = (0, type_resolver_1.getTypeBaseName)(field.type);
610
- if (baseType && baseType.endsWith('Input') && !generatedTypes.has(baseType)) {
701
+ if (baseType &&
702
+ baseType.endsWith('Input') &&
703
+ !generatedTypes.has(baseType)) {
611
704
  typesToGenerate.add(baseType);
612
705
  }
613
706
  }
@@ -633,7 +726,8 @@ function collectPayloadTypeNames(operations) {
633
726
  const payloadTypes = new Set();
634
727
  for (const op of operations) {
635
728
  const baseName = (0, type_resolver_1.getTypeBaseName)(op.returnType);
636
- if (baseName && (baseName.endsWith('Payload') || !baseName.endsWith('Connection'))) {
729
+ if (baseName &&
730
+ (baseName.endsWith('Payload') || !baseName.endsWith('Connection'))) {
637
731
  payloadTypes.add(baseName);
638
732
  }
639
733
  }
@@ -647,8 +741,21 @@ function addPayloadTypes(sourceFile, typeRegistry, usedPayloadTypes, alreadyGene
647
741
  const generatedTypes = new Set(alreadyGeneratedTypes);
648
742
  const typesToGenerate = new Set(Array.from(usedPayloadTypes));
649
743
  const skipTypes = new Set([
650
- 'String', 'Int', 'Float', 'Boolean', 'ID', 'UUID', 'Datetime', 'Date',
651
- 'Time', 'JSON', 'BigInt', 'BigFloat', 'Cursor', 'Query', 'Mutation',
744
+ 'String',
745
+ 'Int',
746
+ 'Float',
747
+ 'Boolean',
748
+ 'ID',
749
+ 'UUID',
750
+ 'Datetime',
751
+ 'Date',
752
+ 'Time',
753
+ 'JSON',
754
+ 'BigInt',
755
+ 'BigFloat',
756
+ 'Cursor',
757
+ 'Query',
758
+ 'Mutation',
652
759
  ]);
653
760
  // Process all types - no artificial limit
654
761
  while (typesToGenerate.size > 0) {
@@ -679,7 +786,9 @@ function addPayloadTypes(sourceFile, typeRegistry, usedPayloadTypes, alreadyGene
679
786
  optional: isNullable,
680
787
  });
681
788
  // Follow nested OBJECT types
682
- if (baseType && !generatedTypes.has(baseType) && !skipTypes.has(baseType)) {
789
+ if (baseType &&
790
+ !generatedTypes.has(baseType) &&
791
+ !skipTypes.has(baseType)) {
683
792
  const nestedType = typeRegistry.get(baseType);
684
793
  if (nestedType?.kind === 'OBJECT') {
685
794
  typesToGenerate.add(baseType);
@@ -733,6 +842,8 @@ function generateInputTypesFile(typeRegistry, usedInputTypes, tables, usedPayloa
733
842
  addEntitySelectTypes(sourceFile, tables, tableByName);
734
843
  // 4. Table filter types
735
844
  addTableFilterTypes(sourceFile, tables);
845
+ // 4b. Table condition types (simple equality filter)
846
+ addTableConditionTypes(sourceFile, tables);
736
847
  // 5. OrderBy types
737
848
  addOrderByTypes(sourceFile, tables);
738
849
  // 6. CRUD input types
@@ -124,7 +124,8 @@ function generateModelFile(table, _useSharedTypes) {
124
124
  before: args?.before,
125
125
  offset: args?.offset,
126
126
  },
127
- '${whereTypeName}'
127
+ '${whereTypeName}',
128
+ '${orderByTypeName}'
128
129
  );
129
130
  return new QueryBuilder({
130
131
  client: this.client,
@@ -105,7 +105,7 @@ export declare function buildFindManyDocument(operationName: string, queryField:
105
105
  after?: string;
106
106
  before?: string;
107
107
  offset?: number;
108
- }, filterTypeName: string): {
108
+ }, filterTypeName: string, orderByTypeName: string): {
109
109
  document: string;
110
110
  variables: Record<string, unknown>;
111
111
  };
@@ -177,7 +177,7 @@ function buildSelections(select, fieldMeta) {
177
177
  /**
178
178
  * Build a findMany query document
179
179
  */
180
- function buildFindManyDocument(operationName, queryField, select, args, filterTypeName) {
180
+ function buildFindManyDocument(operationName, queryField, select, args, filterTypeName, orderByTypeName) {
181
181
  const selections = select ? buildSelections(select) : 'id';
182
182
  // Build variable definitions and query arguments
183
183
  const varDefs = [];
@@ -189,7 +189,7 @@ function buildFindManyDocument(operationName, queryField, select, args, filterTy
189
189
  variables.where = args.where;
190
190
  }
191
191
  if (args.orderBy && args.orderBy.length > 0) {
192
- varDefs.push(`$orderBy: [${operationName}OrderBy!]`);
192
+ varDefs.push(`$orderBy: [${orderByTypeName}!]`);
193
193
  queryArgs.push('orderBy: $orderBy');
194
194
  variables.orderBy = args.orderBy;
195
195
  }
@@ -29,13 +29,13 @@ const SKIP_TYPES = new Set([
29
29
  /**
30
30
  * Type name patterns to skip (regex patterns)
31
31
  *
32
- * Note: We intentionally DO NOT skip Connection, Edge, Filter, or Patch types
33
- * because they may be referenced by custom operations or payload types.
34
- * Only skip Condition and OrderBy which are typically not needed.
32
+ * Note: We intentionally DO NOT skip Connection, Edge, Filter, Patch, Condition,
33
+ * or OrderBy types because they may be referenced by custom operations.
34
+ * Previously Condition and OrderBy were skipped but they ARE needed for
35
+ * custom queries like `schemata`, `apiSchemata`, etc.
35
36
  */
36
37
  const SKIP_TYPE_PATTERNS = [
37
- /Condition$/, // e.g., UserCondition (filter conditions are separate)
38
- /OrderBy$/, // e.g., UsersOrderBy (ordering is handled separately)
38
+ // Currently no patterns are skipped - all types may be needed by custom operations
39
39
  ];
40
40
  // ============================================================================
41
41
  // Type Conversion Utilities
@@ -101,9 +101,14 @@ export declare function getDeleteMutationName(table: CleanTable): string;
101
101
  export declare function getFilterTypeName(table: CleanTable): string;
102
102
  /**
103
103
  * Get PostGraphile OrderBy enum type name
104
- * e.g., "CarsOrderBy"
104
+ * e.g., "CarsOrderBy", "AddressesOrderBy"
105
105
  */
106
106
  export declare function getOrderByTypeName(table: CleanTable): string;
107
+ /**
108
+ * Get PostGraphile Condition type name (simple equality filter)
109
+ * e.g., "CarCondition", "AddressCondition"
110
+ */
111
+ export declare function getConditionTypeName(table: CleanTable): string;
107
112
  /**
108
113
  * Get PostGraphile create input type name
109
114
  * e.g., "CreateCarInput"
@@ -23,6 +23,7 @@ exports.getUpdateMutationName = getUpdateMutationName;
23
23
  exports.getDeleteMutationName = getDeleteMutationName;
24
24
  exports.getFilterTypeName = getFilterTypeName;
25
25
  exports.getOrderByTypeName = getOrderByTypeName;
26
+ exports.getConditionTypeName = getConditionTypeName;
26
27
  exports.getCreateInputTypeName = getCreateInputTypeName;
27
28
  exports.getPatchTypeName = getPatchTypeName;
28
29
  exports.getUpdateInputTypeName = getUpdateInputTypeName;
@@ -38,6 +39,7 @@ exports.getQueryKeyPrefix = getQueryKeyPrefix;
38
39
  exports.getGeneratedFileHeader = getGeneratedFileHeader;
39
40
  exports.indent = indent;
40
41
  const scalars_1 = require("./scalars");
42
+ const pluralize_1 = require("../introspect/pluralize");
41
43
  // ============================================================================
42
44
  // String manipulation
43
45
  // ============================================================================
@@ -75,7 +77,9 @@ function toScreamingSnake(str) {
75
77
  function getTableNames(table) {
76
78
  const typeName = table.name;
77
79
  const singularName = table.inflection?.tableFieldName || lcFirst(typeName);
78
- const pluralName = table.query?.all || table.inflection?.allRows || singularName + 's';
80
+ const pluralName = table.query?.all ||
81
+ table.inflection?.allRows ||
82
+ lcFirst((0, pluralize_1.pluralize)(typeName));
79
83
  const pluralTypeName = ucFirst(pluralName);
80
84
  return {
81
85
  typeName,
@@ -164,13 +168,15 @@ function getDeleteMutationFileName(table) {
164
168
  * Uses inflection from _meta, falls back to convention
165
169
  */
166
170
  function getAllRowsQueryName(table) {
167
- return table.query?.all || table.inflection?.allRows || lcFirst(table.name) + 's';
171
+ return (table.query?.all ||
172
+ table.inflection?.allRows ||
173
+ lcFirst((0, pluralize_1.pluralize)(table.name)));
168
174
  }
169
175
  /**
170
176
  * Get the GraphQL query name for fetching single row
171
177
  */
172
178
  function getSingleRowQueryName(table) {
173
- return table.query?.one || table.inflection?.tableFieldName || lcFirst(table.name);
179
+ return (table.query?.one || table.inflection?.tableFieldName || lcFirst(table.name));
174
180
  }
175
181
  /**
176
182
  * Get the GraphQL mutation name for creating
@@ -202,10 +208,17 @@ function getFilterTypeName(table) {
202
208
  }
203
209
  /**
204
210
  * Get PostGraphile OrderBy enum type name
205
- * e.g., "CarsOrderBy"
211
+ * e.g., "CarsOrderBy", "AddressesOrderBy"
206
212
  */
207
213
  function getOrderByTypeName(table) {
208
- return table.inflection?.orderByType || `${table.name}sOrderBy`;
214
+ return table.inflection?.orderByType || `${(0, pluralize_1.pluralize)(table.name)}OrderBy`;
215
+ }
216
+ /**
217
+ * Get PostGraphile Condition type name (simple equality filter)
218
+ * e.g., "CarCondition", "AddressCondition"
219
+ */
220
+ function getConditionTypeName(table) {
221
+ return table.inflection?.conditionType || `${table.name}Condition`;
209
222
  }
210
223
  /**
211
224
  * Get PostGraphile create input type name
@@ -293,13 +306,15 @@ function getPrimaryKeyInfo(table) {
293
306
  const pk = table.constraints?.primaryKey?.[0];
294
307
  if (!pk || pk.fields.length === 0) {
295
308
  // Fallback: try to find 'id' field in table fields
296
- const idField = table.fields.find(f => f.name.toLowerCase() === 'id');
309
+ const idField = table.fields.find((f) => f.name.toLowerCase() === 'id');
297
310
  if (idField) {
298
- return [{
311
+ return [
312
+ {
299
313
  name: idField.name,
300
314
  gqlType: idField.type.gqlType,
301
315
  tsType: fieldTypeToTs(idField.type),
302
- }];
316
+ },
317
+ ];
303
318
  }
304
319
  // Last resort: assume 'id' of type string (UUID)
305
320
  return [{ name: 'id', gqlType: 'UUID', tsType: 'string' }];
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Generate ORM command - generates Prisma-like ORM client
2
+ * Generate ORM command - generates Prisma-like ORM client from GraphQL schema
3
3
  *
4
4
  * This command:
5
- * 1. Fetches _meta query for table-based CRUD operations
6
- * 2. Fetches __schema introspection for custom operations
5
+ * 1. Fetches schema from endpoint or loads from file
6
+ * 2. Infers table metadata from introspection (replaces _meta)
7
7
  * 3. Generates a Prisma-like ORM client with fluent API
8
8
  */
9
9
  export interface GenerateOrmOptions {
@@ -11,6 +11,8 @@ export interface GenerateOrmOptions {
11
11
  config?: string;
12
12
  /** GraphQL endpoint URL (overrides config) */
13
13
  endpoint?: string;
14
+ /** Path to GraphQL schema file (.graphql) */
15
+ schema?: string;
14
16
  /** Output directory (overrides config) */
15
17
  output?: string;
16
18
  /** Authorization header */