@constructive-io/graphql-codegen 3.3.2 → 4.0.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.
- package/README.md +0 -4
- package/core/ast.js +6 -5
- package/core/codegen/custom-mutations.js +22 -22
- package/core/codegen/custom-queries.js +24 -17
- package/core/codegen/hooks-ast.d.ts +1 -1
- package/core/codegen/hooks-ast.js +22 -5
- package/core/codegen/index.d.ts +1 -1
- package/core/codegen/mutations.js +16 -12
- package/core/codegen/orm/custom-ops-generator.js +37 -3
- package/core/codegen/orm/input-types-generator.js +161 -89
- package/core/codegen/orm/model-generator.js +72 -73
- package/core/codegen/orm/select-types.d.ts +27 -17
- package/core/codegen/queries.js +37 -25
- package/core/codegen/schema-types-generator.js +21 -0
- package/core/codegen/templates/hooks-selection.ts +12 -0
- package/core/codegen/templates/query-builder.ts +103 -59
- package/core/codegen/templates/select-types.ts +59 -33
- package/core/codegen/types.js +26 -0
- package/core/codegen/utils.d.ts +1 -1
- package/core/codegen/utils.js +1 -1
- package/core/custom-ast.js +9 -8
- package/core/database/index.js +2 -3
- package/core/index.d.ts +2 -0
- package/core/index.js +2 -0
- package/core/introspect/infer-tables.js +144 -58
- package/core/introspect/transform-schema.d.ts +1 -1
- package/core/introspect/transform-schema.js +3 -1
- package/esm/core/ast.js +6 -5
- package/esm/core/codegen/custom-mutations.js +23 -23
- package/esm/core/codegen/custom-queries.js +25 -18
- package/esm/core/codegen/hooks-ast.d.ts +1 -1
- package/esm/core/codegen/hooks-ast.js +22 -5
- package/esm/core/codegen/index.d.ts +1 -1
- package/esm/core/codegen/mutations.js +16 -12
- package/esm/core/codegen/orm/custom-ops-generator.js +38 -4
- package/esm/core/codegen/orm/input-types-generator.js +163 -91
- package/esm/core/codegen/orm/model-generator.js +73 -74
- package/esm/core/codegen/orm/select-types.d.ts +27 -17
- package/esm/core/codegen/queries.js +37 -25
- package/esm/core/codegen/schema-types-generator.js +21 -0
- package/esm/core/codegen/types.js +26 -0
- package/esm/core/codegen/utils.d.ts +1 -1
- package/esm/core/codegen/utils.js +1 -1
- package/esm/core/custom-ast.js +9 -8
- package/esm/core/database/index.js +2 -3
- package/esm/core/index.d.ts +2 -0
- package/esm/core/index.js +2 -0
- package/esm/core/introspect/infer-tables.js +144 -58
- package/esm/core/introspect/transform-schema.d.ts +1 -1
- package/esm/core/introspect/transform-schema.js +3 -1
- package/esm/generators/field-selector.js +1 -0
- package/esm/generators/index.d.ts +3 -0
- package/esm/generators/index.js +3 -0
- package/esm/generators/mutations.js +4 -4
- package/esm/generators/select.js +4 -4
- package/esm/index.d.ts +1 -1
- package/esm/index.js +1 -1
- package/esm/types/schema.d.ts +5 -3
- package/generators/field-selector.js +1 -0
- package/generators/index.d.ts +3 -0
- package/generators/index.js +3 -0
- package/generators/mutations.js +3 -3
- package/generators/select.js +3 -3
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/package.json +10 -10
- package/types/schema.d.ts +5 -3
|
@@ -365,6 +365,41 @@ function generateEnumTypes(typeRegistry, enumTypeNames) {
|
|
|
365
365
|
}
|
|
366
366
|
return statements;
|
|
367
367
|
}
|
|
368
|
+
function collectCustomScalarTypes(typeRegistry, tables, excludedTypeNames) {
|
|
369
|
+
const customScalarTypes = new Set();
|
|
370
|
+
const tableTypeNames = new Set(tables.map((table) => table.name));
|
|
371
|
+
for (const [typeName, typeInfo] of typeRegistry) {
|
|
372
|
+
if (typeInfo.kind !== 'SCALAR')
|
|
373
|
+
continue;
|
|
374
|
+
if (scalars_1.SCALAR_NAMES.has(typeName))
|
|
375
|
+
continue;
|
|
376
|
+
if (excludedTypeNames.has(typeName))
|
|
377
|
+
continue;
|
|
378
|
+
customScalarTypes.add(typeName);
|
|
379
|
+
}
|
|
380
|
+
for (const table of tables) {
|
|
381
|
+
for (const field of table.fields) {
|
|
382
|
+
const fieldType = typeof field.type === 'string' ? field.type : field.type.gqlType;
|
|
383
|
+
if (scalars_1.SCALAR_NAMES.has(fieldType))
|
|
384
|
+
continue;
|
|
385
|
+
if (excludedTypeNames.has(fieldType))
|
|
386
|
+
continue;
|
|
387
|
+
if (tableTypeNames.has(fieldType))
|
|
388
|
+
continue;
|
|
389
|
+
if (isLikelyEnumType(fieldType, typeRegistry))
|
|
390
|
+
continue;
|
|
391
|
+
customScalarTypes.add(fieldType);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return Array.from(customScalarTypes).sort();
|
|
395
|
+
}
|
|
396
|
+
function generateCustomScalarTypes(customScalarTypes) {
|
|
397
|
+
if (customScalarTypes.length === 0)
|
|
398
|
+
return [];
|
|
399
|
+
const statements = customScalarTypes.map((scalarType) => createExportedTypeAlias(scalarType, 'unknown'));
|
|
400
|
+
addSectionComment(statements, 'Custom Scalar Types');
|
|
401
|
+
return statements;
|
|
402
|
+
}
|
|
368
403
|
// ============================================================================
|
|
369
404
|
// Entity Types Generator (AST-based)
|
|
370
405
|
// ============================================================================
|
|
@@ -546,15 +581,12 @@ function buildSelectTypeLiteral(table, tableByName) {
|
|
|
546
581
|
for (const relation of table.relations.belongsTo) {
|
|
547
582
|
if (relation.fieldName) {
|
|
548
583
|
const relatedTypeName = getRelatedTypeName(relation.referencesTable, tableByName);
|
|
549
|
-
const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
return selectProp;
|
|
556
|
-
})(),
|
|
557
|
-
]),
|
|
584
|
+
const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
585
|
+
(() => {
|
|
586
|
+
const selectProp = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${relatedTypeName}Select`))));
|
|
587
|
+
selectProp.optional = false;
|
|
588
|
+
return selectProp;
|
|
589
|
+
})(),
|
|
558
590
|
])));
|
|
559
591
|
prop.optional = true;
|
|
560
592
|
members.push(prop);
|
|
@@ -566,30 +598,27 @@ function buildSelectTypeLiteral(table, tableByName) {
|
|
|
566
598
|
const relatedTypeName = getRelatedTypeName(relation.referencedByTable, tableByName);
|
|
567
599
|
const filterName = getRelatedFilterName(relation.referencedByTable, tableByName);
|
|
568
600
|
const orderByName = getRelatedOrderByName(relation.referencedByTable, tableByName);
|
|
569
|
-
const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
return p;
|
|
591
|
-
})(),
|
|
592
|
-
]),
|
|
601
|
+
const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
602
|
+
(() => {
|
|
603
|
+
const p = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${relatedTypeName}Select`))));
|
|
604
|
+
p.optional = false;
|
|
605
|
+
return p;
|
|
606
|
+
})(),
|
|
607
|
+
(() => {
|
|
608
|
+
const p = t.tsPropertySignature(t.identifier('first'), t.tsTypeAnnotation(t.tsNumberKeyword()));
|
|
609
|
+
p.optional = true;
|
|
610
|
+
return p;
|
|
611
|
+
})(),
|
|
612
|
+
(() => {
|
|
613
|
+
const p = t.tsPropertySignature(t.identifier('filter'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterName))));
|
|
614
|
+
p.optional = true;
|
|
615
|
+
return p;
|
|
616
|
+
})(),
|
|
617
|
+
(() => {
|
|
618
|
+
const p = t.tsPropertySignature(t.identifier('orderBy'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(orderByName)))));
|
|
619
|
+
p.optional = true;
|
|
620
|
+
return p;
|
|
621
|
+
})(),
|
|
593
622
|
])));
|
|
594
623
|
prop.optional = true;
|
|
595
624
|
members.push(prop);
|
|
@@ -601,30 +630,27 @@ function buildSelectTypeLiteral(table, tableByName) {
|
|
|
601
630
|
const relatedTypeName = getRelatedTypeName(relation.rightTable, tableByName);
|
|
602
631
|
const filterName = getRelatedFilterName(relation.rightTable, tableByName);
|
|
603
632
|
const orderByName = getRelatedOrderByName(relation.rightTable, tableByName);
|
|
604
|
-
const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
return p;
|
|
626
|
-
})(),
|
|
627
|
-
]),
|
|
633
|
+
const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
634
|
+
(() => {
|
|
635
|
+
const p = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${relatedTypeName}Select`))));
|
|
636
|
+
p.optional = false;
|
|
637
|
+
return p;
|
|
638
|
+
})(),
|
|
639
|
+
(() => {
|
|
640
|
+
const p = t.tsPropertySignature(t.identifier('first'), t.tsTypeAnnotation(t.tsNumberKeyword()));
|
|
641
|
+
p.optional = true;
|
|
642
|
+
return p;
|
|
643
|
+
})(),
|
|
644
|
+
(() => {
|
|
645
|
+
const p = t.tsPropertySignature(t.identifier('filter'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterName))));
|
|
646
|
+
p.optional = true;
|
|
647
|
+
return p;
|
|
648
|
+
})(),
|
|
649
|
+
(() => {
|
|
650
|
+
const p = t.tsPropertySignature(t.identifier('orderBy'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(orderByName)))));
|
|
651
|
+
p.optional = true;
|
|
652
|
+
return p;
|
|
653
|
+
})(),
|
|
628
654
|
])));
|
|
629
655
|
prop.optional = true;
|
|
630
656
|
members.push(prop);
|
|
@@ -634,15 +660,12 @@ function buildSelectTypeLiteral(table, tableByName) {
|
|
|
634
660
|
for (const relation of table.relations.hasOne) {
|
|
635
661
|
if (relation.fieldName) {
|
|
636
662
|
const relatedTypeName = getRelatedTypeName(relation.referencedByTable, tableByName);
|
|
637
|
-
const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
return selectProp;
|
|
644
|
-
})(),
|
|
645
|
-
]),
|
|
663
|
+
const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
664
|
+
(() => {
|
|
665
|
+
const selectProp = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${relatedTypeName}Select`))));
|
|
666
|
+
selectProp.optional = false;
|
|
667
|
+
return selectProp;
|
|
668
|
+
})(),
|
|
646
669
|
])));
|
|
647
670
|
prop.optional = true;
|
|
648
671
|
members.push(prop);
|
|
@@ -784,7 +807,7 @@ function generateOrderByTypes(tables) {
|
|
|
784
807
|
/**
|
|
785
808
|
* Build the nested data object fields for Create input
|
|
786
809
|
*/
|
|
787
|
-
function
|
|
810
|
+
function buildCreateDataFieldsFromTable(table) {
|
|
788
811
|
const fields = [];
|
|
789
812
|
for (const field of table.fields) {
|
|
790
813
|
if (EXCLUDED_MUTATION_FIELDS.includes(field.name))
|
|
@@ -798,12 +821,60 @@ function buildCreateDataFields(table) {
|
|
|
798
821
|
}
|
|
799
822
|
return fields;
|
|
800
823
|
}
|
|
824
|
+
/**
|
|
825
|
+
* Build Create input fields from schema Input types when available.
|
|
826
|
+
*
|
|
827
|
+
* This follows the actual GraphQL input shape:
|
|
828
|
+
* `CreateXInput { clientMutationId?, x: XInput! }`
|
|
829
|
+
*/
|
|
830
|
+
function buildCreateDataFieldsFromSchema(table, typeRegistry) {
|
|
831
|
+
const createInputTypeName = (0, utils_1.getCreateInputTypeName)(table);
|
|
832
|
+
const createInputType = typeRegistry.get(createInputTypeName);
|
|
833
|
+
if (!createInputType ||
|
|
834
|
+
createInputType.kind !== 'INPUT_OBJECT' ||
|
|
835
|
+
!createInputType.inputFields) {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
const { singularName } = (0, utils_1.getTableNames)(table);
|
|
839
|
+
const entityArg = createInputType.inputFields.find((field) => field.name === singularName) ??
|
|
840
|
+
createInputType.inputFields.find((field) => field.name !== 'clientMutationId');
|
|
841
|
+
if (!entityArg)
|
|
842
|
+
return null;
|
|
843
|
+
const entityInputTypeName = (0, type_resolver_1.getTypeBaseName)(entityArg.type);
|
|
844
|
+
if (!entityInputTypeName)
|
|
845
|
+
return null;
|
|
846
|
+
const entityInputType = typeRegistry.get(entityInputTypeName);
|
|
847
|
+
if (!entityInputType ||
|
|
848
|
+
entityInputType.kind !== 'INPUT_OBJECT' ||
|
|
849
|
+
!entityInputType.inputFields) {
|
|
850
|
+
return null;
|
|
851
|
+
}
|
|
852
|
+
const fields = [];
|
|
853
|
+
for (const field of entityInputType.inputFields) {
|
|
854
|
+
if (EXCLUDED_MUTATION_FIELDS.includes(field.name)) {
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
fields.push({
|
|
858
|
+
name: field.name,
|
|
859
|
+
type: typeRefToTs(field.type),
|
|
860
|
+
optional: !isRequired(field.type),
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
return fields;
|
|
864
|
+
}
|
|
865
|
+
/**
|
|
866
|
+
* Build Create input fields, preferring schema-derived Input object fields.
|
|
867
|
+
*/
|
|
868
|
+
function buildCreateDataFields(table, typeRegistry) {
|
|
869
|
+
return (buildCreateDataFieldsFromSchema(table, typeRegistry) ??
|
|
870
|
+
buildCreateDataFieldsFromTable(table));
|
|
871
|
+
}
|
|
801
872
|
/**
|
|
802
873
|
* Build Create input interface as AST
|
|
803
874
|
*/
|
|
804
|
-
function buildCreateInputInterface(table) {
|
|
875
|
+
function buildCreateInputInterface(table, typeRegistry) {
|
|
805
876
|
const { typeName, singularName } = (0, utils_1.getTableNames)(table);
|
|
806
|
-
const fields = buildCreateDataFields(table);
|
|
877
|
+
const fields = buildCreateDataFields(table, typeRegistry);
|
|
807
878
|
// Build the nested object type for the entity data
|
|
808
879
|
const nestedProps = fields.map((field) => {
|
|
809
880
|
const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(parseTypeString(field.type)));
|
|
@@ -847,7 +918,7 @@ function buildPatchProperties(table) {
|
|
|
847
918
|
/**
|
|
848
919
|
* Generate CRUD input type statements for a table
|
|
849
920
|
*/
|
|
850
|
-
function generateCrudInputTypes(table) {
|
|
921
|
+
function generateCrudInputTypes(table, typeRegistry) {
|
|
851
922
|
const statements = [];
|
|
852
923
|
const { typeName } = (0, utils_1.getTableNames)(table);
|
|
853
924
|
const patchName = `${typeName}Patch`;
|
|
@@ -856,14 +927,15 @@ function generateCrudInputTypes(table) {
|
|
|
856
927
|
const pkFieldName = pkField?.name ?? 'id';
|
|
857
928
|
const pkFieldTsType = pkField?.tsType ?? 'string';
|
|
858
929
|
// Create input
|
|
859
|
-
statements.push(buildCreateInputInterface(table));
|
|
930
|
+
statements.push(buildCreateInputInterface(table, typeRegistry));
|
|
860
931
|
// Patch interface
|
|
861
932
|
statements.push(createExportedInterface(patchName, buildPatchProperties(table)));
|
|
862
|
-
// Update input
|
|
933
|
+
// Update input - v5 uses entity-specific patch field names (e.g., "userPatch")
|
|
934
|
+
const patchFieldName = table.query?.patchFieldName ?? (0, utils_1.lcFirst)(typeName) + 'Patch';
|
|
863
935
|
statements.push(createExportedInterface(`Update${typeName}Input`, [
|
|
864
936
|
{ name: 'clientMutationId', type: 'string', optional: true },
|
|
865
937
|
{ name: pkFieldName, type: pkFieldTsType, optional: false },
|
|
866
|
-
{ name:
|
|
938
|
+
{ name: patchFieldName, type: patchName, optional: false },
|
|
867
939
|
]));
|
|
868
940
|
// Delete input
|
|
869
941
|
statements.push(createExportedInterface(`Delete${typeName}Input`, [
|
|
@@ -875,10 +947,10 @@ function generateCrudInputTypes(table) {
|
|
|
875
947
|
/**
|
|
876
948
|
* Generate all CRUD input type statements
|
|
877
949
|
*/
|
|
878
|
-
function generateAllCrudInputTypes(tables) {
|
|
950
|
+
function generateAllCrudInputTypes(tables, typeRegistry) {
|
|
879
951
|
const statements = [];
|
|
880
952
|
for (const table of tables) {
|
|
881
|
-
statements.push(...generateCrudInputTypes(table));
|
|
953
|
+
statements.push(...generateCrudInputTypes(table, typeRegistry));
|
|
882
954
|
}
|
|
883
955
|
if (statements.length > 0) {
|
|
884
956
|
addSectionComment(statements, 'CRUD Input Types');
|
|
@@ -1081,15 +1153,12 @@ function generatePayloadTypes(typeRegistry, usedPayloadTypes, alreadyGeneratedTy
|
|
|
1081
1153
|
const nestedType = baseType ? typeRegistry.get(baseType) : null;
|
|
1082
1154
|
let propType;
|
|
1083
1155
|
if (nestedType?.kind === 'OBJECT') {
|
|
1084
|
-
propType = t.
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
return p;
|
|
1091
|
-
})(),
|
|
1092
|
-
]),
|
|
1156
|
+
propType = t.tsTypeLiteral([
|
|
1157
|
+
(() => {
|
|
1158
|
+
const p = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${baseType}Select`))));
|
|
1159
|
+
p.optional = false;
|
|
1160
|
+
return p;
|
|
1161
|
+
})(),
|
|
1093
1162
|
]);
|
|
1094
1163
|
}
|
|
1095
1164
|
else {
|
|
@@ -1160,13 +1229,16 @@ function generateInputTypesFile(typeRegistry, usedInputTypes, tables, usedPayloa
|
|
|
1160
1229
|
const tablesList = tables ?? [];
|
|
1161
1230
|
const hasTables = tablesList.length > 0;
|
|
1162
1231
|
const tableByName = new Map(tablesList.map((table) => [table.name, table]));
|
|
1232
|
+
const enumTypes = hasTables
|
|
1233
|
+
? collectEnumTypesFromTables(tablesList, typeRegistry)
|
|
1234
|
+
: new Set();
|
|
1235
|
+
const customScalarTypes = collectCustomScalarTypes(typeRegistry, tablesList, enumTypes);
|
|
1163
1236
|
// 1. Scalar filter types
|
|
1164
1237
|
statements.push(...generateScalarFilterTypes());
|
|
1165
1238
|
// 2. Enum types used by table fields
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
}
|
|
1239
|
+
statements.push(...generateEnumTypes(typeRegistry, enumTypes));
|
|
1240
|
+
// 2b. Unknown/custom scalar aliases for schema-specific scalars
|
|
1241
|
+
statements.push(...generateCustomScalarTypes(customScalarTypes));
|
|
1170
1242
|
// 3. Entity and relation types (if tables provided)
|
|
1171
1243
|
if (hasTables) {
|
|
1172
1244
|
statements.push(...generateEntityTypes(tablesList));
|
|
@@ -1181,7 +1253,7 @@ function generateInputTypesFile(typeRegistry, usedInputTypes, tables, usedPayloa
|
|
|
1181
1253
|
// 5. OrderBy types
|
|
1182
1254
|
statements.push(...generateOrderByTypes(tablesList));
|
|
1183
1255
|
// 6. CRUD input types
|
|
1184
|
-
statements.push(...generateAllCrudInputTypes(tablesList));
|
|
1256
|
+
statements.push(...generateAllCrudInputTypes(tablesList, typeRegistry));
|
|
1185
1257
|
}
|
|
1186
1258
|
// 6b. Connection fields map (runtime metadata for buildSelections)
|
|
1187
1259
|
// Always emit this export so generated model/custom-op imports stay valid.
|
|
@@ -50,7 +50,7 @@ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false
|
|
|
50
50
|
decl.importKind = typeOnly ? 'type' : 'value';
|
|
51
51
|
return decl;
|
|
52
52
|
}
|
|
53
|
-
function buildMethodBody(builderFn, args, operation, typeName, fieldName) {
|
|
53
|
+
function buildMethodBody(builderFn, args, operation, typeName, fieldName, extraProps = []) {
|
|
54
54
|
const destructureDecl = t.variableDeclaration('const', [
|
|
55
55
|
t.variableDeclarator(t.objectPattern([
|
|
56
56
|
t.objectProperty(t.identifier('document'), t.identifier('document'), false, true),
|
|
@@ -65,6 +65,7 @@ function buildMethodBody(builderFn, args, operation, typeName, fieldName) {
|
|
|
65
65
|
t.objectProperty(t.identifier('fieldName'), t.stringLiteral(fieldName)),
|
|
66
66
|
t.objectProperty(t.identifier('document'), t.identifier('document'), false, true),
|
|
67
67
|
t.objectProperty(t.identifier('variables'), t.identifier('variables'), false, true),
|
|
68
|
+
...extraProps,
|
|
68
69
|
]),
|
|
69
70
|
]));
|
|
70
71
|
return [destructureDecl, returnStmt];
|
|
@@ -75,10 +76,6 @@ function createClassMethod(name, typeParameters, params, returnType, body) {
|
|
|
75
76
|
method.returnType = returnType;
|
|
76
77
|
return method;
|
|
77
78
|
}
|
|
78
|
-
function createDeclareMethod(name, typeParameters, params, returnType) {
|
|
79
|
-
const method = t.tsDeclareMethod(null, t.identifier(name), typeParameters, params, returnType);
|
|
80
|
-
return method;
|
|
81
|
-
}
|
|
82
79
|
function createTypeParam(constraintTypeName, defaultType) {
|
|
83
80
|
const param = t.tsTypeParameter(t.tsTypeReference(t.identifier(constraintTypeName)), defaultType ?? null, 'S');
|
|
84
81
|
return t.tsTypeParameterDeclaration([param]);
|
|
@@ -122,6 +119,8 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
122
119
|
const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
|
|
123
120
|
const pkField = pkFields[0];
|
|
124
121
|
const pluralQueryName = table.query?.all ?? pluralName;
|
|
122
|
+
const singleQueryName = table.query?.one;
|
|
123
|
+
const singleResultFieldName = (0, utils_1.getSingleRowQueryName)(table);
|
|
125
124
|
const createMutationName = table.query?.create ?? `create${typeName}`;
|
|
126
125
|
const updateMutationName = table.query?.update;
|
|
127
126
|
const deleteMutationName = table.query?.delete;
|
|
@@ -166,7 +165,6 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
166
165
|
classBody.push(t.classMethod('constructor', t.identifier('constructor'), [paramProp], t.blockStatement([])));
|
|
167
166
|
// Reusable type reference factories
|
|
168
167
|
const sRef = () => t.tsTypeReference(t.identifier('S'));
|
|
169
|
-
const selectRef = () => t.tsTypeReference(t.identifier(selectTypeName));
|
|
170
168
|
const pkTsType = () => tsTypeFromPrimitive(pkField.tsType);
|
|
171
169
|
// ── findMany ───────────────────────────────────────────────────────────
|
|
172
170
|
{
|
|
@@ -185,17 +183,12 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
185
183
|
])))),
|
|
186
184
|
]),
|
|
187
185
|
])));
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
186
|
+
const implParam = t.identifier('args');
|
|
187
|
+
implParam.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
191
188
|
argsType(sRef()),
|
|
192
189
|
t.tsTypeLiteral([requiredSelectProp()]),
|
|
193
190
|
strictSelectGuard(selectTypeName),
|
|
194
191
|
]));
|
|
195
|
-
classBody.push(createDeclareMethod('findMany', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
|
|
196
|
-
// Implementation
|
|
197
|
-
const implParam = t.identifier('args');
|
|
198
|
-
implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
|
|
199
192
|
const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
|
|
200
193
|
const bodyArgs = [
|
|
201
194
|
t.stringLiteral(typeName),
|
|
@@ -217,7 +210,7 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
217
210
|
t.stringLiteral(orderByTypeName),
|
|
218
211
|
t.identifier('connectionFieldsMap'),
|
|
219
212
|
];
|
|
220
|
-
classBody.push(createClassMethod('findMany',
|
|
213
|
+
classBody.push(createClassMethod('findMany', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildFindManyDocument', bodyArgs, 'query', typeName, pluralQueryName)));
|
|
221
214
|
}
|
|
222
215
|
// ── findFirst ──────────────────────────────────────────────────────────
|
|
223
216
|
{
|
|
@@ -235,17 +228,12 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
235
228
|
]))),
|
|
236
229
|
]),
|
|
237
230
|
])));
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
231
|
+
const implParam = t.identifier('args');
|
|
232
|
+
implParam.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
241
233
|
argsType(sRef()),
|
|
242
234
|
t.tsTypeLiteral([requiredSelectProp()]),
|
|
243
235
|
strictSelectGuard(selectTypeName),
|
|
244
236
|
]));
|
|
245
|
-
classBody.push(createDeclareMethod('findFirst', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
|
|
246
|
-
// Implementation
|
|
247
|
-
const implParam = t.identifier('args');
|
|
248
|
-
implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
|
|
249
237
|
const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
|
|
250
238
|
const bodyArgs = [
|
|
251
239
|
t.stringLiteral(typeName),
|
|
@@ -257,15 +245,13 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
257
245
|
t.stringLiteral(whereTypeName),
|
|
258
246
|
t.identifier('connectionFieldsMap'),
|
|
259
247
|
];
|
|
260
|
-
classBody.push(createClassMethod('findFirst',
|
|
248
|
+
classBody.push(createClassMethod('findFirst', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildFindFirstDocument', bodyArgs, 'query', typeName, pluralQueryName)));
|
|
261
249
|
}
|
|
262
250
|
// ── findOne ────────────────────────────────────────────────────────────
|
|
263
|
-
|
|
264
|
-
if (singleQueryName && (0, utils_1.hasValidPrimaryKey)(table)) {
|
|
265
|
-
const pkGqlType = pkField.gqlType.replace(/!/g, '') + '!';
|
|
251
|
+
if ((0, utils_1.hasValidPrimaryKey)(table)) {
|
|
266
252
|
const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
|
|
267
253
|
t.tsTypeLiteral([
|
|
268
|
-
t.tsPropertySignature(t.identifier(
|
|
254
|
+
t.tsPropertySignature(t.identifier(singleResultFieldName), t.tsTypeAnnotation(t.tsUnionType([
|
|
269
255
|
t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
|
|
270
256
|
t.tsTypeReference(t.identifier(relationTypeName)),
|
|
271
257
|
sel,
|
|
@@ -279,33 +265,59 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
279
265
|
prop.optional = false;
|
|
280
266
|
return prop;
|
|
281
267
|
};
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
268
|
+
const implParam = t.identifier('args');
|
|
269
|
+
implParam.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
285
270
|
t.tsTypeLiteral([pkProp(), requiredSelectProp()]),
|
|
286
271
|
strictSelectGuard(selectTypeName),
|
|
287
272
|
]));
|
|
288
|
-
classBody.push(createDeclareMethod('findOne', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
|
|
289
|
-
// Implementation
|
|
290
|
-
const implParam = t.identifier('args');
|
|
291
|
-
implParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
292
|
-
pkProp(),
|
|
293
|
-
(() => {
|
|
294
|
-
const prop = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(selectTypeName))));
|
|
295
|
-
return prop;
|
|
296
|
-
})(),
|
|
297
|
-
]));
|
|
298
273
|
const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
274
|
+
if (singleQueryName) {
|
|
275
|
+
const pkGqlType = pkField.gqlType.replace(/!/g, '') + '!';
|
|
276
|
+
const bodyArgs = [
|
|
277
|
+
t.stringLiteral(typeName),
|
|
278
|
+
t.stringLiteral(singleQueryName),
|
|
279
|
+
t.memberExpression(t.identifier('args'), t.identifier(pkField.name)),
|
|
280
|
+
selectExpr,
|
|
281
|
+
t.stringLiteral(pkField.name),
|
|
282
|
+
t.stringLiteral(pkGqlType),
|
|
283
|
+
t.identifier('connectionFieldsMap'),
|
|
284
|
+
];
|
|
285
|
+
classBody.push(createClassMethod('findOne', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildFindOneDocument', bodyArgs, 'query', typeName, singleResultFieldName)));
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
const idExpr = t.memberExpression(t.identifier('args'), t.identifier(pkField.name));
|
|
289
|
+
const findOneArgs = t.objectExpression([
|
|
290
|
+
t.objectProperty(t.identifier('where'), t.objectExpression([
|
|
291
|
+
t.objectProperty(t.identifier(pkField.name), t.objectExpression([
|
|
292
|
+
t.objectProperty(t.identifier('equalTo'), idExpr),
|
|
293
|
+
])),
|
|
294
|
+
])),
|
|
295
|
+
t.objectProperty(t.identifier('first'), t.numericLiteral(1)),
|
|
296
|
+
]);
|
|
297
|
+
const bodyArgs = [
|
|
298
|
+
t.stringLiteral(typeName),
|
|
299
|
+
t.stringLiteral(pluralQueryName),
|
|
300
|
+
selectExpr,
|
|
301
|
+
findOneArgs,
|
|
302
|
+
t.stringLiteral(whereTypeName),
|
|
303
|
+
t.stringLiteral(orderByTypeName),
|
|
304
|
+
t.identifier('connectionFieldsMap'),
|
|
305
|
+
];
|
|
306
|
+
const firstNodeExpr = t.optionalMemberExpression(t.optionalMemberExpression(t.memberExpression(t.identifier('data'), t.identifier(pluralQueryName)), t.identifier('nodes'), false, true), t.numericLiteral(0), true, true);
|
|
307
|
+
const transformDataParam = t.identifier('data');
|
|
308
|
+
const transformedNodesProp = t.tsPropertySignature(t.identifier('nodes'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
|
|
309
|
+
t.tsTypeReference(t.identifier(relationTypeName)),
|
|
310
|
+
sRef(),
|
|
311
|
+
])))));
|
|
312
|
+
transformedNodesProp.optional = true;
|
|
313
|
+
const transformedCollectionProp = t.tsPropertySignature(t.identifier(pluralQueryName), t.tsTypeAnnotation(t.tsTypeLiteral([transformedNodesProp])));
|
|
314
|
+
transformedCollectionProp.optional = true;
|
|
315
|
+
transformDataParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeLiteral([transformedCollectionProp]));
|
|
316
|
+
const transformFn = t.arrowFunctionExpression([transformDataParam], t.objectExpression([
|
|
317
|
+
t.objectProperty(t.stringLiteral(singleResultFieldName), t.logicalExpression('??', firstNodeExpr, t.nullLiteral())),
|
|
318
|
+
]));
|
|
319
|
+
classBody.push(createClassMethod('findOne', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildFindManyDocument', bodyArgs, 'query', typeName, singleResultFieldName, [t.objectProperty(t.identifier('transform'), transformFn)])));
|
|
320
|
+
}
|
|
309
321
|
}
|
|
310
322
|
// ── create ─────────────────────────────────────────────────────────────
|
|
311
323
|
{
|
|
@@ -321,17 +333,12 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
321
333
|
]))),
|
|
322
334
|
]),
|
|
323
335
|
])));
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
336
|
+
const implParam = t.identifier('args');
|
|
337
|
+
implParam.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
327
338
|
argsType(sRef()),
|
|
328
339
|
t.tsTypeLiteral([requiredSelectProp()]),
|
|
329
340
|
strictSelectGuard(selectTypeName),
|
|
330
341
|
]));
|
|
331
|
-
classBody.push(createDeclareMethod('create', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
|
|
332
|
-
// Implementation
|
|
333
|
-
const implParam = t.identifier('args');
|
|
334
|
-
implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
|
|
335
342
|
const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
|
|
336
343
|
const bodyArgs = [
|
|
337
344
|
t.stringLiteral(typeName),
|
|
@@ -342,7 +349,7 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
342
349
|
t.stringLiteral(createInputTypeName),
|
|
343
350
|
t.identifier('connectionFieldsMap'),
|
|
344
351
|
];
|
|
345
|
-
classBody.push(createClassMethod('create',
|
|
352
|
+
classBody.push(createClassMethod('create', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildCreateDocument', bodyArgs, 'mutation', typeName, createMutationName)));
|
|
346
353
|
}
|
|
347
354
|
// ── update ─────────────────────────────────────────────────────────────
|
|
348
355
|
if (updateMutationName) {
|
|
@@ -368,18 +375,14 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
368
375
|
]))),
|
|
369
376
|
]),
|
|
370
377
|
])));
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
378
|
+
const implParam = t.identifier('args');
|
|
379
|
+
implParam.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
374
380
|
argsType(sRef()),
|
|
375
381
|
t.tsTypeLiteral([requiredSelectProp()]),
|
|
376
382
|
strictSelectGuard(selectTypeName),
|
|
377
383
|
]));
|
|
378
|
-
classBody.push(createDeclareMethod('update', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
|
|
379
|
-
// Implementation
|
|
380
|
-
const implParam = t.identifier('args');
|
|
381
|
-
implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
|
|
382
384
|
const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
|
|
385
|
+
const patchFieldName = table.query?.patchFieldName ?? (0, utils_1.lcFirst)(typeName) + 'Patch';
|
|
383
386
|
const bodyArgs = [
|
|
384
387
|
t.stringLiteral(typeName),
|
|
385
388
|
t.stringLiteral(updateMutationName),
|
|
@@ -389,9 +392,10 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
389
392
|
t.memberExpression(t.identifier('args'), t.identifier('data')),
|
|
390
393
|
t.stringLiteral(updateInputTypeName),
|
|
391
394
|
t.stringLiteral(pkField.name),
|
|
395
|
+
t.stringLiteral(patchFieldName),
|
|
392
396
|
t.identifier('connectionFieldsMap'),
|
|
393
397
|
];
|
|
394
|
-
classBody.push(createClassMethod('update',
|
|
398
|
+
classBody.push(createClassMethod('update', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildUpdateByPkDocument', bodyArgs, 'mutation', typeName, updateMutationName)));
|
|
395
399
|
}
|
|
396
400
|
// ── delete ─────────────────────────────────────────────────────────────
|
|
397
401
|
if (deleteMutationName) {
|
|
@@ -413,17 +417,12 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
413
417
|
]))),
|
|
414
418
|
]),
|
|
415
419
|
])));
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
420
|
+
const implParam = t.identifier('args');
|
|
421
|
+
implParam.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
|
|
419
422
|
argsType(sRef()),
|
|
420
423
|
t.tsTypeLiteral([requiredSelectProp()]),
|
|
421
424
|
strictSelectGuard(selectTypeName),
|
|
422
425
|
]));
|
|
423
|
-
classBody.push(createDeclareMethod('delete', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
|
|
424
|
-
// Implementation
|
|
425
|
-
const implParam = t.identifier('args');
|
|
426
|
-
implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
|
|
427
426
|
const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
|
|
428
427
|
const bodyArgs = [
|
|
429
428
|
t.stringLiteral(typeName),
|
|
@@ -435,7 +434,7 @@ function generateModelFile(table, _useSharedTypes) {
|
|
|
435
434
|
selectExpr,
|
|
436
435
|
t.identifier('connectionFieldsMap'),
|
|
437
436
|
];
|
|
438
|
-
classBody.push(createClassMethod('delete',
|
|
437
|
+
classBody.push(createClassMethod('delete', createTypeParam(selectTypeName), [implParam], retType(sRef()), buildMethodBody('buildDeleteByPkDocument', bodyArgs, 'mutation', typeName, deleteMutationName)));
|
|
439
438
|
}
|
|
440
439
|
const classDecl = t.classDeclaration(t.identifier(modelName), null, t.classBody(classBody));
|
|
441
440
|
statements.push(t.exportNamedDeclaration(classDecl));
|