@constructive-io/graphql-codegen 4.37.2 → 4.38.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/core/codegen/babel-ast.js +4 -3
- package/core/codegen/hooks-ast.js +4 -3
- package/core/codegen/orm/input-types-generator.js +32 -4
- package/core/codegen/orm/select-types.d.ts +4 -0
- package/core/codegen/templates/query-builder.ts +32 -0
- package/esm/core/codegen/babel-ast.js +4 -3
- package/esm/core/codegen/hooks-ast.js +4 -3
- package/esm/core/codegen/orm/input-types-generator.js +32 -4
- package/esm/core/codegen/orm/select-types.d.ts +4 -0
- package/esm/types/schema.d.ts +16 -0
- package/package.json +4 -4
- package/types/schema.d.ts +16 -0
|
@@ -94,9 +94,10 @@ exports.commentLine = commentLine;
|
|
|
94
94
|
* Add a leading JSDoc comment to a node
|
|
95
95
|
*/
|
|
96
96
|
function addJSDocComment(node, lines) {
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
const sanitized = lines.map((line) => line.replace(/\*\//g, '*\\/'));
|
|
98
|
+
const commentText = sanitized.length === 1
|
|
99
|
+
? `* ${sanitized[0]} `
|
|
100
|
+
: `*\n${sanitized.map((line) => ` * ${line}`).join('\n')}\n `;
|
|
100
101
|
if (!node.leadingComments) {
|
|
101
102
|
node.leadingComments = [];
|
|
102
103
|
}
|
|
@@ -392,9 +392,10 @@ function destructureParamsWithSelectionAndScope(restName) {
|
|
|
392
392
|
// JSDoc comment helpers
|
|
393
393
|
// ============================================================================
|
|
394
394
|
function addJSDocComment(node, lines) {
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
395
|
+
const sanitized = lines.map((line) => line.replace(/\*\//g, '*\\/'));
|
|
396
|
+
const text = sanitized.length === 1
|
|
397
|
+
? `* ${sanitized[0]} `
|
|
398
|
+
: `*\n${sanitized.map((line) => ` * ${line}`).join('\n')}\n `;
|
|
398
399
|
if (!node.leadingComments) {
|
|
399
400
|
node.leadingComments = [];
|
|
400
401
|
}
|
|
@@ -588,12 +588,40 @@ function generateEntityWithRelations(tables) {
|
|
|
588
588
|
*/
|
|
589
589
|
function buildSelectTypeLiteral(table, tableByName) {
|
|
590
590
|
const members = [];
|
|
591
|
-
// Add scalar fields
|
|
591
|
+
// Add scalar fields (and fields with arguments)
|
|
592
592
|
for (const field of table.fields) {
|
|
593
593
|
if (!(0, utils_1.isRelationField)(field.name, table)) {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
594
|
+
if (field.args && field.args.length > 0) {
|
|
595
|
+
// Field with arguments (e.g. requestUploadUrl on bucket types)
|
|
596
|
+
const argMembers = field.args.map((arg) => {
|
|
597
|
+
const tsType = typeRefToTs(arg.type);
|
|
598
|
+
const argProp = t.tsPropertySignature(t.identifier(arg.name), t.tsTypeAnnotation(parseTypeString(tsType)));
|
|
599
|
+
argProp.optional = !arg.isRequired;
|
|
600
|
+
return argProp;
|
|
601
|
+
});
|
|
602
|
+
const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
603
|
+
(() => {
|
|
604
|
+
const argsProp = t.tsPropertySignature(t.identifier('args'), t.tsTypeAnnotation(t.tsTypeLiteral(argMembers)));
|
|
605
|
+
argsProp.optional = false;
|
|
606
|
+
return argsProp;
|
|
607
|
+
})(),
|
|
608
|
+
(() => {
|
|
609
|
+
const selectProp = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
|
|
610
|
+
t.tsStringKeyword(),
|
|
611
|
+
t.tsBooleanKeyword(),
|
|
612
|
+
]))));
|
|
613
|
+
selectProp.optional = true;
|
|
614
|
+
return selectProp;
|
|
615
|
+
})(),
|
|
616
|
+
])));
|
|
617
|
+
prop.optional = true;
|
|
618
|
+
members.push(prop);
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(t.tsBooleanKeyword()));
|
|
622
|
+
prop.optional = true;
|
|
623
|
+
members.push(prop);
|
|
624
|
+
}
|
|
597
625
|
}
|
|
598
626
|
}
|
|
599
627
|
// Add belongsTo relations
|
|
@@ -37,6 +37,7 @@ export type SelectConfig<TFields extends string> = {
|
|
|
37
37
|
*/
|
|
38
38
|
export interface NestedSelectConfig {
|
|
39
39
|
select?: Record<string, boolean | NestedSelectConfig>;
|
|
40
|
+
args?: Record<string, unknown>;
|
|
40
41
|
first?: number;
|
|
41
42
|
last?: number;
|
|
42
43
|
after?: string;
|
|
@@ -101,6 +102,9 @@ export type HookStrictSelect<S, Shape> = S extends DeepExact<S, Shape, 5> ? {} :
|
|
|
101
102
|
*/
|
|
102
103
|
export type InferSelectResult<TEntity, TSelect> = TSelect extends undefined ? TEntity : {
|
|
103
104
|
[K in keyof TSelect as TSelect[K] extends false | undefined ? never : K]: TSelect[K] extends true ? K extends keyof TEntity ? TEntity[K] : never : TSelect[K] extends {
|
|
105
|
+
args: Record<string, unknown>;
|
|
106
|
+
select: infer NestedSelect;
|
|
107
|
+
} ? K extends keyof TEntity ? NonNullable<TEntity[K]> extends ConnectionResult<infer NodeType> ? ConnectionResult<InferSelectResult<NodeType, NestedSelect>> : InferSelectResult<NonNullable<TEntity[K]>, NestedSelect> | (null extends TEntity[K] ? null : never) : never : TSelect[K] extends {
|
|
104
108
|
select: infer NestedSelect;
|
|
105
109
|
} ? K extends keyof TEntity ? NonNullable<TEntity[K]> extends ConnectionResult<infer NodeType> ? ConnectionResult<InferSelectResult<NodeType, NestedSelect>> : InferSelectResult<NonNullable<TEntity[K]>, NestedSelect> | (null extends TEntity[K] ? null : never) : never : K extends keyof TEntity ? TEntity[K] : never;
|
|
106
110
|
};
|
|
@@ -138,12 +138,44 @@ export function buildSelections(
|
|
|
138
138
|
if (typeof value === 'object' && value !== null) {
|
|
139
139
|
const nested = value as {
|
|
140
140
|
select?: Record<string, unknown>;
|
|
141
|
+
args?: Record<string, unknown>;
|
|
141
142
|
first?: number;
|
|
142
143
|
filter?: Record<string, unknown>;
|
|
143
144
|
orderBy?: string[];
|
|
144
145
|
connection?: boolean;
|
|
145
146
|
};
|
|
146
147
|
|
|
148
|
+
// Field with arguments (e.g. requestUploadUrl on bucket types)
|
|
149
|
+
if (nested.args && typeof nested.args === 'object') {
|
|
150
|
+
const fieldArgs = Object.entries(nested.args).map(
|
|
151
|
+
([argName, argValue]) =>
|
|
152
|
+
t.argument({ name: argName, value: buildValueAst(argValue) }),
|
|
153
|
+
);
|
|
154
|
+
const nestedSelect = nested.select;
|
|
155
|
+
if (nestedSelect && typeof nestedSelect === 'object') {
|
|
156
|
+
const subSelections = Object.entries(nestedSelect)
|
|
157
|
+
.filter(([, v]) => v)
|
|
158
|
+
.map(([name]) => t.field({ name }));
|
|
159
|
+
fields.push(
|
|
160
|
+
t.field({
|
|
161
|
+
name: key,
|
|
162
|
+
args: fieldArgs.length ? fieldArgs : undefined,
|
|
163
|
+
selectionSet: subSelections.length
|
|
164
|
+
? t.selectionSet({ selections: subSelections })
|
|
165
|
+
: undefined,
|
|
166
|
+
}),
|
|
167
|
+
);
|
|
168
|
+
} else {
|
|
169
|
+
fields.push(
|
|
170
|
+
t.field({
|
|
171
|
+
name: key,
|
|
172
|
+
args: fieldArgs.length ? fieldArgs : undefined,
|
|
173
|
+
}),
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
|
|
147
179
|
if (!nested.select || typeof nested.select !== 'object') {
|
|
148
180
|
throw new Error(
|
|
149
181
|
`Invalid selection for field "${key}": nested selections must include a "select" object.`,
|
|
@@ -45,9 +45,10 @@ export const commentLine = (value) => {
|
|
|
45
45
|
* Add a leading JSDoc comment to a node
|
|
46
46
|
*/
|
|
47
47
|
export function addJSDocComment(node, lines) {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
const sanitized = lines.map((line) => line.replace(/\*\//g, '*\\/'));
|
|
49
|
+
const commentText = sanitized.length === 1
|
|
50
|
+
? `* ${sanitized[0]} `
|
|
51
|
+
: `*\n${sanitized.map((line) => ` * ${line}`).join('\n')}\n `;
|
|
51
52
|
if (!node.leadingComments) {
|
|
52
53
|
node.leadingComments = [];
|
|
53
54
|
}
|
|
@@ -294,9 +294,10 @@ export function destructureParamsWithSelectionAndScope(restName) {
|
|
|
294
294
|
// JSDoc comment helpers
|
|
295
295
|
// ============================================================================
|
|
296
296
|
export function addJSDocComment(node, lines) {
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
297
|
+
const sanitized = lines.map((line) => line.replace(/\*\//g, '*\\/'));
|
|
298
|
+
const text = sanitized.length === 1
|
|
299
|
+
? `* ${sanitized[0]} `
|
|
300
|
+
: `*\n${sanitized.map((line) => ` * ${line}`).join('\n')}\n `;
|
|
300
301
|
if (!node.leadingComments) {
|
|
301
302
|
node.leadingComments = [];
|
|
302
303
|
}
|
|
@@ -550,12 +550,40 @@ function generateEntityWithRelations(tables) {
|
|
|
550
550
|
*/
|
|
551
551
|
function buildSelectTypeLiteral(table, tableByName) {
|
|
552
552
|
const members = [];
|
|
553
|
-
// Add scalar fields
|
|
553
|
+
// Add scalar fields (and fields with arguments)
|
|
554
554
|
for (const field of table.fields) {
|
|
555
555
|
if (!isRelationField(field.name, table)) {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
556
|
+
if (field.args && field.args.length > 0) {
|
|
557
|
+
// Field with arguments (e.g. requestUploadUrl on bucket types)
|
|
558
|
+
const argMembers = field.args.map((arg) => {
|
|
559
|
+
const tsType = typeRefToTs(arg.type);
|
|
560
|
+
const argProp = t.tsPropertySignature(t.identifier(arg.name), t.tsTypeAnnotation(parseTypeString(tsType)));
|
|
561
|
+
argProp.optional = !arg.isRequired;
|
|
562
|
+
return argProp;
|
|
563
|
+
});
|
|
564
|
+
const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
565
|
+
(() => {
|
|
566
|
+
const argsProp = t.tsPropertySignature(t.identifier('args'), t.tsTypeAnnotation(t.tsTypeLiteral(argMembers)));
|
|
567
|
+
argsProp.optional = false;
|
|
568
|
+
return argsProp;
|
|
569
|
+
})(),
|
|
570
|
+
(() => {
|
|
571
|
+
const selectProp = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([
|
|
572
|
+
t.tsStringKeyword(),
|
|
573
|
+
t.tsBooleanKeyword(),
|
|
574
|
+
]))));
|
|
575
|
+
selectProp.optional = true;
|
|
576
|
+
return selectProp;
|
|
577
|
+
})(),
|
|
578
|
+
])));
|
|
579
|
+
prop.optional = true;
|
|
580
|
+
members.push(prop);
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(t.tsBooleanKeyword()));
|
|
584
|
+
prop.optional = true;
|
|
585
|
+
members.push(prop);
|
|
586
|
+
}
|
|
559
587
|
}
|
|
560
588
|
}
|
|
561
589
|
// Add belongsTo relations
|
|
@@ -37,6 +37,7 @@ export type SelectConfig<TFields extends string> = {
|
|
|
37
37
|
*/
|
|
38
38
|
export interface NestedSelectConfig {
|
|
39
39
|
select?: Record<string, boolean | NestedSelectConfig>;
|
|
40
|
+
args?: Record<string, unknown>;
|
|
40
41
|
first?: number;
|
|
41
42
|
last?: number;
|
|
42
43
|
after?: string;
|
|
@@ -101,6 +102,9 @@ export type HookStrictSelect<S, Shape> = S extends DeepExact<S, Shape, 5> ? {} :
|
|
|
101
102
|
*/
|
|
102
103
|
export type InferSelectResult<TEntity, TSelect> = TSelect extends undefined ? TEntity : {
|
|
103
104
|
[K in keyof TSelect as TSelect[K] extends false | undefined ? never : K]: TSelect[K] extends true ? K extends keyof TEntity ? TEntity[K] : never : TSelect[K] extends {
|
|
105
|
+
args: Record<string, unknown>;
|
|
106
|
+
select: infer NestedSelect;
|
|
107
|
+
} ? K extends keyof TEntity ? NonNullable<TEntity[K]> extends ConnectionResult<infer NodeType> ? ConnectionResult<InferSelectResult<NodeType, NestedSelect>> : InferSelectResult<NonNullable<TEntity[K]>, NestedSelect> | (null extends TEntity[K] ? null : never) : never : TSelect[K] extends {
|
|
104
108
|
select: infer NestedSelect;
|
|
105
109
|
} ? K extends keyof TEntity ? NonNullable<TEntity[K]> extends ConnectionResult<infer NodeType> ? ConnectionResult<InferSelectResult<NodeType, NestedSelect>> : InferSelectResult<NonNullable<TEntity[K]>, NestedSelect> | (null extends TEntity[K] ? null : never) : never : K extends keyof TEntity ? TEntity[K] : never;
|
|
106
110
|
};
|
package/esm/types/schema.d.ts
CHANGED
|
@@ -112,6 +112,22 @@ export interface Field {
|
|
|
112
112
|
isNotNull?: boolean | null;
|
|
113
113
|
/** Whether the column has a DEFAULT value (inferred by comparing entity vs CreateInput field nullability) */
|
|
114
114
|
hasDefault?: boolean | null;
|
|
115
|
+
/** Arguments for computed fields (e.g. requestUploadUrl on bucket types) */
|
|
116
|
+
args?: FieldArgument[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Argument on a computed field (not a root operation)
|
|
120
|
+
*/
|
|
121
|
+
export interface FieldArgument {
|
|
122
|
+
name: string;
|
|
123
|
+
/** GraphQL type reference */
|
|
124
|
+
type: TypeRef;
|
|
125
|
+
/** Whether this argument is required (NON_NULL) */
|
|
126
|
+
isRequired: boolean;
|
|
127
|
+
/** Description from schema */
|
|
128
|
+
description?: string;
|
|
129
|
+
/** Default value (as string) */
|
|
130
|
+
defaultValue?: string;
|
|
115
131
|
}
|
|
116
132
|
/**
|
|
117
133
|
* Field type information from PostGraphile introspection
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/graphql-codegen",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.38.0",
|
|
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.
|
|
59
|
+
"@constructive-io/graphql-query": "^3.21.0",
|
|
60
60
|
"@constructive-io/graphql-types": "^3.8.0",
|
|
61
61
|
"@inquirerer/utils": "^3.3.5",
|
|
62
62
|
"@pgpmjs/core": "^6.16.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.8.0",
|
|
67
|
-
"graphile-schema": "^1.18.
|
|
67
|
+
"graphile-schema": "^1.18.3",
|
|
68
68
|
"graphql": "16.13.0",
|
|
69
69
|
"inflekt": "^0.7.1",
|
|
70
70
|
"inquirerer": "^4.7.0",
|
|
@@ -100,5 +100,5 @@
|
|
|
100
100
|
"tsx": "^4.21.0",
|
|
101
101
|
"typescript": "^5.9.3"
|
|
102
102
|
},
|
|
103
|
-
"gitHead": "
|
|
103
|
+
"gitHead": "97ec8e14f2b0855b0ee0bc732a082e1a91301b64"
|
|
104
104
|
}
|
package/types/schema.d.ts
CHANGED
|
@@ -112,6 +112,22 @@ export interface Field {
|
|
|
112
112
|
isNotNull?: boolean | null;
|
|
113
113
|
/** Whether the column has a DEFAULT value (inferred by comparing entity vs CreateInput field nullability) */
|
|
114
114
|
hasDefault?: boolean | null;
|
|
115
|
+
/** Arguments for computed fields (e.g. requestUploadUrl on bucket types) */
|
|
116
|
+
args?: FieldArgument[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Argument on a computed field (not a root operation)
|
|
120
|
+
*/
|
|
121
|
+
export interface FieldArgument {
|
|
122
|
+
name: string;
|
|
123
|
+
/** GraphQL type reference */
|
|
124
|
+
type: TypeRef;
|
|
125
|
+
/** Whether this argument is required (NON_NULL) */
|
|
126
|
+
isRequired: boolean;
|
|
127
|
+
/** Description from schema */
|
|
128
|
+
description?: string;
|
|
129
|
+
/** Default value (as string) */
|
|
130
|
+
defaultValue?: string;
|
|
115
131
|
}
|
|
116
132
|
/**
|
|
117
133
|
* Field type information from PostGraphile introspection
|