@constructive-io/graphql-codegen 4.47.8 → 4.47.10

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.
@@ -35,7 +35,7 @@ function generateOrm(options) {
35
35
  content: selectTypesFile.content,
36
36
  });
37
37
  // 2. Generate model files
38
- const modelFiles = (0, model_generator_1.generateAllModelFiles)(tables, useSharedTypes);
38
+ const modelFiles = (0, model_generator_1.generateAllModelFiles)(tables, useSharedTypes, typeRegistry);
39
39
  for (const modelFile of modelFiles) {
40
40
  files.push({
41
41
  path: `models/${modelFile.fileName}`,
@@ -1,9 +1,9 @@
1
- import type { Table } from '../../../types/schema';
1
+ import type { Table, TypeRegistry } from '../../../types/schema';
2
2
  export interface GeneratedModelFile {
3
3
  fileName: string;
4
4
  content: string;
5
5
  modelName: string;
6
6
  tableName: string;
7
7
  }
8
- export declare function generateModelFile(table: Table, _useSharedTypes: boolean, options?: Record<string, never>, allTables?: Table[]): GeneratedModelFile;
9
- export declare function generateAllModelFiles(tables: Table[], useSharedTypes: boolean): GeneratedModelFile[];
8
+ export declare function generateModelFile(table: Table, _useSharedTypes: boolean, options?: Record<string, never>, allTables?: Table[], typeRegistry?: TypeRegistry): GeneratedModelFile;
9
+ export declare function generateAllModelFiles(tables: Table[], useSharedTypes: boolean, typeRegistry?: TypeRegistry): GeneratedModelFile[];
@@ -103,7 +103,39 @@ function strictSelectGuard(selectTypeName) {
103
103
  t.tsTypeReference(t.identifier(selectTypeName)),
104
104
  ]));
105
105
  }
106
- function generateModelFile(table, _useSharedTypes, options, allTables) {
106
+ /**
107
+ * Discover extra required fields on a mutation input type beyond the standard
108
+ * ones (clientMutationId, PK fields, patch field). PostGraphile adds these for
109
+ * partitioned tables (e.g. databaseId as the partition key).
110
+ */
111
+ function getExtraInputKeys(inputTypeName, pkFieldNames, patchFieldName, typeRegistry) {
112
+ if (!typeRegistry)
113
+ return [];
114
+ const inputType = typeRegistry.get(inputTypeName);
115
+ if (!inputType || inputType.kind !== 'INPUT_OBJECT' || !inputType.inputFields)
116
+ return [];
117
+ const skip = new Set(['clientMutationId', ...(patchFieldName ? [patchFieldName] : [])]);
118
+ for (const pk of pkFieldNames)
119
+ skip.add(pk);
120
+ const extras = [];
121
+ for (const field of inputType.inputFields) {
122
+ if (skip.has(field.name))
123
+ continue;
124
+ if (field.type.kind !== 'NON_NULL')
125
+ continue;
126
+ const innerName = field.type.ofType?.name;
127
+ if (!innerName)
128
+ continue;
129
+ let tsType = 'string';
130
+ if (innerName === 'Int' || innerName === 'Float' || innerName === 'BigFloat')
131
+ tsType = 'number';
132
+ else if (innerName === 'Boolean')
133
+ tsType = 'boolean';
134
+ extras.push({ name: field.name, gqlType: innerName, tsType });
135
+ }
136
+ return extras;
137
+ }
138
+ function generateModelFile(table, _useSharedTypes, options, allTables, typeRegistry) {
107
139
  const { typeName, singularName, pluralName } = (0, utils_1.getTableNames)(table);
108
140
  const modelName = `${typeName}Model`;
109
141
  const baseFileName = (0, utils_1.lcFirst)(typeName);
@@ -114,7 +146,7 @@ function generateModelFile(table, _useSharedTypes, options, allTables) {
114
146
  const whereTypeName = (0, utils_1.getFilterTypeName)(table);
115
147
  const orderByTypeName = (0, utils_1.getOrderByTypeName)(table);
116
148
  const createInputTypeName = `Create${typeName}Input`;
117
- const updateInputTypeName = `Update${typeName}Input`;
149
+ const updateInputTypeName = (0, utils_1.getUpdateInputTypeName)(table);
118
150
  const patchTypeName = `${typeName}Patch`;
119
151
  const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
120
152
  const pkField = pkFields[0];
@@ -401,12 +433,19 @@ function generateModelFile(table, _useSharedTypes, options, allTables) {
401
433
  }
402
434
  // ── update ─────────────────────────────────────────────────────────────
403
435
  if (updateMutationName) {
436
+ const patchFieldName = table.query?.patchFieldName ?? (0, utils_1.lcFirst)(typeName) + 'Patch';
437
+ const updateExtraKeys = getExtraInputKeys(updateInputTypeName, new Set(pkFields.map((pk) => pk.name)), patchFieldName, typeRegistry);
404
438
  const whereLiteral = () => t.tsTypeLiteral([
405
439
  (() => {
406
440
  const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType()));
407
441
  prop.optional = false;
408
442
  return prop;
409
443
  })(),
444
+ ...updateExtraKeys.map((ek) => {
445
+ const prop = t.tsPropertySignature(t.identifier(ek.name), t.tsTypeAnnotation(tsTypeFromPrimitive(ek.tsType)));
446
+ prop.optional = false;
447
+ return prop;
448
+ }),
410
449
  ]);
411
450
  const argsType = (sel) => t.tsTypeReference(t.identifier('UpdateArgs'), t.tsTypeParameterInstantiation([
412
451
  sel,
@@ -430,7 +469,10 @@ function generateModelFile(table, _useSharedTypes, options, allTables) {
430
469
  strictSelectGuard(selectTypeName),
431
470
  ]));
432
471
  const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
433
- const patchFieldName = table.query?.patchFieldName ?? (0, utils_1.lcFirst)(typeName) + 'Patch';
472
+ // Build extraKeys object for partitioned table fields
473
+ const extraKeysArg = updateExtraKeys.length > 0
474
+ ? t.objectExpression(updateExtraKeys.map((ek) => t.objectProperty(t.identifier(ek.name), t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(ek.name)))))
475
+ : t.identifier('undefined');
434
476
  const bodyArgs = [
435
477
  t.stringLiteral(typeName),
436
478
  t.stringLiteral(updateMutationName),
@@ -442,17 +484,26 @@ function generateModelFile(table, _useSharedTypes, options, allTables) {
442
484
  t.stringLiteral(pkField.name),
443
485
  t.stringLiteral(patchFieldName),
444
486
  t.identifier('connectionFieldsMap'),
487
+ extraKeysArg,
445
488
  ];
446
489
  classBody.push(createClassMethod('update', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildUpdateByPkDocument', bodyArgs, 'mutation', typeName, updateMutationName)));
447
490
  }
448
491
  // ── delete ─────────────────────────────────────────────────────────────
449
492
  if (deleteMutationName) {
450
- // Build where type with ALL PK fields (supports composite PKs)
451
- const whereLiteral = () => t.tsTypeLiteral(pkFields.map((pk) => {
452
- const prop = t.tsPropertySignature(t.identifier(pk.name), t.tsTypeAnnotation(tsTypeFromPrimitive(pk.tsType ?? 'string')));
453
- prop.optional = false;
454
- return prop;
455
- }));
493
+ const deleteExtraKeys = getExtraInputKeys(deleteInputTypeName, new Set(pkFields.map((pk) => pk.name)), null, typeRegistry);
494
+ // Build where type with ALL PK fields + extra keys (supports composite PKs + partition keys)
495
+ const whereLiteral = () => t.tsTypeLiteral([
496
+ ...pkFields.map((pk) => {
497
+ const prop = t.tsPropertySignature(t.identifier(pk.name), t.tsTypeAnnotation(tsTypeFromPrimitive(pk.tsType ?? 'string')));
498
+ prop.optional = false;
499
+ return prop;
500
+ }),
501
+ ...deleteExtraKeys.map((ek) => {
502
+ const prop = t.tsPropertySignature(t.identifier(ek.name), t.tsTypeAnnotation(tsTypeFromPrimitive(ek.tsType)));
503
+ prop.optional = false;
504
+ return prop;
505
+ }),
506
+ ]);
456
507
  const argsType = (sel) => t.tsTypeReference(t.identifier('DeleteArgs'), t.tsTypeParameterInstantiation([whereLiteral(), sel]));
457
508
  const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
458
509
  t.tsTypeLiteral([
@@ -471,8 +522,11 @@ function generateModelFile(table, _useSharedTypes, options, allTables) {
471
522
  strictSelectGuard(selectTypeName),
472
523
  ]));
473
524
  const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
474
- // Build keys object: { field1: args.where.field1, field2: args.where.field2, ... }
475
- const keysObj = t.objectExpression(pkFields.map((pk) => t.objectProperty(t.identifier(pk.name), t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(pk.name)))));
525
+ // Build keys object: { field1: args.where.field1, ... } including extra keys
526
+ const keysObj = t.objectExpression([
527
+ ...pkFields.map((pk) => t.objectProperty(t.identifier(pk.name), t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(pk.name)))),
528
+ ...deleteExtraKeys.map((ek) => t.objectProperty(t.identifier(ek.name), t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(ek.name)))),
529
+ ]);
476
530
  const bodyArgs = [
477
531
  t.stringLiteral(typeName),
478
532
  t.stringLiteral(deleteMutationName),
@@ -748,6 +802,6 @@ function generateModelFile(table, _useSharedTypes, options, allTables) {
748
802
  tableName: table.name,
749
803
  };
750
804
  }
751
- function generateAllModelFiles(tables, useSharedTypes) {
752
- return tables.map((table) => generateModelFile(table, useSharedTypes, undefined, tables));
805
+ function generateAllModelFiles(tables, useSharedTypes, typeRegistry) {
806
+ return tables.map((table) => generateModelFile(table, useSharedTypes, undefined, tables, typeRegistry));
753
807
  }
@@ -509,6 +509,7 @@ export function buildUpdateByPkDocument<TSelect, TData>(
509
509
  idFieldName: string,
510
510
  patchFieldName: string,
511
511
  connectionFieldsMap?: Record<string, Record<string, string>>,
512
+ extraKeys?: Record<string, unknown>,
512
513
  ): { document: string; variables: Record<string, unknown> } {
513
514
  const selections = select
514
515
  ? buildSelections(
@@ -533,6 +534,7 @@ export function buildUpdateByPkDocument<TSelect, TData>(
533
534
  variables: {
534
535
  input: {
535
536
  [idFieldName]: id,
537
+ ...extraKeys,
536
538
  [patchFieldName]: data,
537
539
  },
538
540
  },
@@ -31,7 +31,7 @@ export function generateOrm(options) {
31
31
  content: selectTypesFile.content,
32
32
  });
33
33
  // 2. Generate model files
34
- const modelFiles = generateAllModelFiles(tables, useSharedTypes);
34
+ const modelFiles = generateAllModelFiles(tables, useSharedTypes, typeRegistry);
35
35
  for (const modelFile of modelFiles) {
36
36
  files.push({
37
37
  path: `models/${modelFile.fileName}`,
@@ -1,9 +1,9 @@
1
- import type { Table } from '../../../types/schema';
1
+ import type { Table, TypeRegistry } from '../../../types/schema';
2
2
  export interface GeneratedModelFile {
3
3
  fileName: string;
4
4
  content: string;
5
5
  modelName: string;
6
6
  tableName: string;
7
7
  }
8
- export declare function generateModelFile(table: Table, _useSharedTypes: boolean, options?: Record<string, never>, allTables?: Table[]): GeneratedModelFile;
9
- export declare function generateAllModelFiles(tables: Table[], useSharedTypes: boolean): GeneratedModelFile[];
8
+ export declare function generateModelFile(table: Table, _useSharedTypes: boolean, options?: Record<string, never>, allTables?: Table[], typeRegistry?: TypeRegistry): GeneratedModelFile;
9
+ export declare function generateAllModelFiles(tables: Table[], useSharedTypes: boolean, typeRegistry?: TypeRegistry): GeneratedModelFile[];
@@ -7,7 +7,7 @@
7
7
  import * as t from '@babel/types';
8
8
  import { singularize } from 'inflekt';
9
9
  import { generateCode } from '../babel-ast';
10
- import { getCreateInputTypeName, getCreateMutationName, getDeleteInputTypeName, getDeleteMutationName, getFilterTypeName, getGeneratedFileHeader, getOrderByTypeName, getPrimaryKeyInfo, getTableNames, hasValidPrimaryKey, lcFirst, ucFirst, } from '../utils';
10
+ import { getCreateInputTypeName, getCreateMutationName, getDeleteInputTypeName, getDeleteMutationName, getFilterTypeName, getGeneratedFileHeader, getOrderByTypeName, getPrimaryKeyInfo, getTableNames, getUpdateInputTypeName, hasValidPrimaryKey, lcFirst, ucFirst, } from '../utils';
11
11
  function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
12
12
  const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
13
13
  const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
@@ -66,7 +66,39 @@ function strictSelectGuard(selectTypeName) {
66
66
  t.tsTypeReference(t.identifier(selectTypeName)),
67
67
  ]));
68
68
  }
69
- export function generateModelFile(table, _useSharedTypes, options, allTables) {
69
+ /**
70
+ * Discover extra required fields on a mutation input type beyond the standard
71
+ * ones (clientMutationId, PK fields, patch field). PostGraphile adds these for
72
+ * partitioned tables (e.g. databaseId as the partition key).
73
+ */
74
+ function getExtraInputKeys(inputTypeName, pkFieldNames, patchFieldName, typeRegistry) {
75
+ if (!typeRegistry)
76
+ return [];
77
+ const inputType = typeRegistry.get(inputTypeName);
78
+ if (!inputType || inputType.kind !== 'INPUT_OBJECT' || !inputType.inputFields)
79
+ return [];
80
+ const skip = new Set(['clientMutationId', ...(patchFieldName ? [patchFieldName] : [])]);
81
+ for (const pk of pkFieldNames)
82
+ skip.add(pk);
83
+ const extras = [];
84
+ for (const field of inputType.inputFields) {
85
+ if (skip.has(field.name))
86
+ continue;
87
+ if (field.type.kind !== 'NON_NULL')
88
+ continue;
89
+ const innerName = field.type.ofType?.name;
90
+ if (!innerName)
91
+ continue;
92
+ let tsType = 'string';
93
+ if (innerName === 'Int' || innerName === 'Float' || innerName === 'BigFloat')
94
+ tsType = 'number';
95
+ else if (innerName === 'Boolean')
96
+ tsType = 'boolean';
97
+ extras.push({ name: field.name, gqlType: innerName, tsType });
98
+ }
99
+ return extras;
100
+ }
101
+ export function generateModelFile(table, _useSharedTypes, options, allTables, typeRegistry) {
70
102
  const { typeName, singularName, pluralName } = getTableNames(table);
71
103
  const modelName = `${typeName}Model`;
72
104
  const baseFileName = lcFirst(typeName);
@@ -77,7 +109,7 @@ export function generateModelFile(table, _useSharedTypes, options, allTables) {
77
109
  const whereTypeName = getFilterTypeName(table);
78
110
  const orderByTypeName = getOrderByTypeName(table);
79
111
  const createInputTypeName = `Create${typeName}Input`;
80
- const updateInputTypeName = `Update${typeName}Input`;
112
+ const updateInputTypeName = getUpdateInputTypeName(table);
81
113
  const patchTypeName = `${typeName}Patch`;
82
114
  const pkFields = getPrimaryKeyInfo(table);
83
115
  const pkField = pkFields[0];
@@ -364,12 +396,19 @@ export function generateModelFile(table, _useSharedTypes, options, allTables) {
364
396
  }
365
397
  // ── update ─────────────────────────────────────────────────────────────
366
398
  if (updateMutationName) {
399
+ const patchFieldName = table.query?.patchFieldName ?? lcFirst(typeName) + 'Patch';
400
+ const updateExtraKeys = getExtraInputKeys(updateInputTypeName, new Set(pkFields.map((pk) => pk.name)), patchFieldName, typeRegistry);
367
401
  const whereLiteral = () => t.tsTypeLiteral([
368
402
  (() => {
369
403
  const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType()));
370
404
  prop.optional = false;
371
405
  return prop;
372
406
  })(),
407
+ ...updateExtraKeys.map((ek) => {
408
+ const prop = t.tsPropertySignature(t.identifier(ek.name), t.tsTypeAnnotation(tsTypeFromPrimitive(ek.tsType)));
409
+ prop.optional = false;
410
+ return prop;
411
+ }),
373
412
  ]);
374
413
  const argsType = (sel) => t.tsTypeReference(t.identifier('UpdateArgs'), t.tsTypeParameterInstantiation([
375
414
  sel,
@@ -393,7 +432,10 @@ export function generateModelFile(table, _useSharedTypes, options, allTables) {
393
432
  strictSelectGuard(selectTypeName),
394
433
  ]));
395
434
  const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
396
- const patchFieldName = table.query?.patchFieldName ?? lcFirst(typeName) + 'Patch';
435
+ // Build extraKeys object for partitioned table fields
436
+ const extraKeysArg = updateExtraKeys.length > 0
437
+ ? t.objectExpression(updateExtraKeys.map((ek) => t.objectProperty(t.identifier(ek.name), t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(ek.name)))))
438
+ : t.identifier('undefined');
397
439
  const bodyArgs = [
398
440
  t.stringLiteral(typeName),
399
441
  t.stringLiteral(updateMutationName),
@@ -405,17 +447,26 @@ export function generateModelFile(table, _useSharedTypes, options, allTables) {
405
447
  t.stringLiteral(pkField.name),
406
448
  t.stringLiteral(patchFieldName),
407
449
  t.identifier('connectionFieldsMap'),
450
+ extraKeysArg,
408
451
  ];
409
452
  classBody.push(createClassMethod('update', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildUpdateByPkDocument', bodyArgs, 'mutation', typeName, updateMutationName)));
410
453
  }
411
454
  // ── delete ─────────────────────────────────────────────────────────────
412
455
  if (deleteMutationName) {
413
- // Build where type with ALL PK fields (supports composite PKs)
414
- const whereLiteral = () => t.tsTypeLiteral(pkFields.map((pk) => {
415
- const prop = t.tsPropertySignature(t.identifier(pk.name), t.tsTypeAnnotation(tsTypeFromPrimitive(pk.tsType ?? 'string')));
416
- prop.optional = false;
417
- return prop;
418
- }));
456
+ const deleteExtraKeys = getExtraInputKeys(deleteInputTypeName, new Set(pkFields.map((pk) => pk.name)), null, typeRegistry);
457
+ // Build where type with ALL PK fields + extra keys (supports composite PKs + partition keys)
458
+ const whereLiteral = () => t.tsTypeLiteral([
459
+ ...pkFields.map((pk) => {
460
+ const prop = t.tsPropertySignature(t.identifier(pk.name), t.tsTypeAnnotation(tsTypeFromPrimitive(pk.tsType ?? 'string')));
461
+ prop.optional = false;
462
+ return prop;
463
+ }),
464
+ ...deleteExtraKeys.map((ek) => {
465
+ const prop = t.tsPropertySignature(t.identifier(ek.name), t.tsTypeAnnotation(tsTypeFromPrimitive(ek.tsType)));
466
+ prop.optional = false;
467
+ return prop;
468
+ }),
469
+ ]);
419
470
  const argsType = (sel) => t.tsTypeReference(t.identifier('DeleteArgs'), t.tsTypeParameterInstantiation([whereLiteral(), sel]));
420
471
  const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
421
472
  t.tsTypeLiteral([
@@ -434,8 +485,11 @@ export function generateModelFile(table, _useSharedTypes, options, allTables) {
434
485
  strictSelectGuard(selectTypeName),
435
486
  ]));
436
487
  const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
437
- // Build keys object: { field1: args.where.field1, field2: args.where.field2, ... }
438
- const keysObj = t.objectExpression(pkFields.map((pk) => t.objectProperty(t.identifier(pk.name), t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(pk.name)))));
488
+ // Build keys object: { field1: args.where.field1, ... } including extra keys
489
+ const keysObj = t.objectExpression([
490
+ ...pkFields.map((pk) => t.objectProperty(t.identifier(pk.name), t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(pk.name)))),
491
+ ...deleteExtraKeys.map((ek) => t.objectProperty(t.identifier(ek.name), t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(ek.name)))),
492
+ ]);
439
493
  const bodyArgs = [
440
494
  t.stringLiteral(typeName),
441
495
  t.stringLiteral(deleteMutationName),
@@ -711,6 +765,6 @@ export function generateModelFile(table, _useSharedTypes, options, allTables) {
711
765
  tableName: table.name,
712
766
  };
713
767
  }
714
- export function generateAllModelFiles(tables, useSharedTypes) {
715
- return tables.map((table) => generateModelFile(table, useSharedTypes, undefined, tables));
768
+ export function generateAllModelFiles(tables, useSharedTypes, typeRegistry) {
769
+ return tables.map((table) => generateModelFile(table, useSharedTypes, undefined, tables, typeRegistry));
716
770
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-codegen",
3
- "version": "4.47.8",
3
+ "version": "4.47.10",
4
4
  "description": "GraphQL SDK generator for Constructive databases with React Query hooks",
5
5
  "keywords": [
6
6
  "graphql",
@@ -56,7 +56,7 @@
56
56
  "@0no-co/graphql.web": "^1.1.2",
57
57
  "@babel/generator": "^7.29.1",
58
58
  "@babel/types": "^7.29.0",
59
- "@constructive-io/graphql-query": "^3.27.6",
59
+ "@constructive-io/graphql-query": "^3.27.7",
60
60
  "@constructive-io/graphql-types": "^3.12.0",
61
61
  "@inquirerer/utils": "^3.3.7",
62
62
  "@pgpmjs/core": "^6.24.0",
@@ -64,7 +64,7 @@
64
64
  "deepmerge": "^4.3.1",
65
65
  "find-and-require-package-json": "^0.9.1",
66
66
  "gql-ast": "^3.11.0",
67
- "graphile-schema": "^1.22.6",
67
+ "graphile-schema": "^1.22.7",
68
68
  "graphql": "16.13.0",
69
69
  "inflekt": "^0.7.1",
70
70
  "inquirerer": "^4.8.1",
@@ -100,5 +100,5 @@
100
100
  "tsx": "^4.21.0",
101
101
  "typescript": "^5.9.3"
102
102
  },
103
- "gitHead": "2558a0cdb58c815933af8bfe6769cd59014c77cf"
103
+ "gitHead": "bca385f6d3d1311477e2c4ef36f9d49dec401c60"
104
104
  }