Skip to content

Commit f8d0ea6

Browse files
committed
Support readonly() in query-builder
1 parent 51ce2bb commit f8d0ea6

File tree

7 files changed

+55
-23
lines changed

7 files changed

+55
-23
lines changed

dprint.json

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"singleBodyPosition": "nextLine",
1313
"nextControlFlowPosition": "sameLine",
1414
"trailingCommas": "never",
15-
"operatorPosition": "nextLine",
15+
"operatorPosition": "sameLine",
1616
"preferHanging": false,
1717
"preferSingleLine": false,
1818
"arrowFunction.useParentheses": "force",
@@ -68,11 +68,7 @@
6868
"emphasisKind": "underscores",
6969
"strongKind": "asterisks"
7070
},
71-
"excludes": [
72-
"target/",
73-
"**/node_modules",
74-
"**/*-lock.json"
75-
],
71+
"excludes": ["target/", "**/node_modules", "**/*-lock.json"],
7672
"plugins": [
7773
"./node_modules/@dprint/typescript/plugin.wasm",
7874
"./node_modules/@dprint/json/plugin.wasm",

eslint.config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ export default [
1515
'prettier/prettier': 'off',
1616
'dprint/typescript': ['error', { configFile: 'dprint.json' }],
1717
'import/order': 'off',
18-
'@stylistic/member-delimiter-style': 'off'
18+
'@stylistic/member-delimiter-style': 'off',
19+
'@stylistic/operator-linebreak': 'off'
1920
}
2021
},
2122
{

source/zod-graphql-client/client.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,12 @@ export function createClientFactory(dependencies: CreateClientDependencies): Cre
110110
const variableDefinitions = extractVariableDefinitions(variables);
111111
const variableValues = extractVariableValues(variables);
112112

113-
const serializedQuery = operationType === 'query'
114-
? buildGraphqlQuery(schema, {
113+
const serializedQuery = operationType === 'query' ?
114+
buildGraphqlQuery(schema, {
115115
operationName: options.operationName,
116116
variableDefinitions
117-
})
118-
: buildGraphqlMutation(schema, {
117+
}) :
118+
buildGraphqlMutation(schema, {
119119
operationName: options.operationName,
120120
variableDefinitions
121121
});

source/zod-graphql-fake-client/fake-client.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ export function createFakeGraphqlClient(clientOptions: FakeClientOptions = {}):
4747
const variableDefinitions = extractVariableDefinitions(variables);
4848
const variableValues = extractVariableValues(variables);
4949

50-
const serializedQuery = type === 'query'
51-
? buildGraphqlQuery(schema, {
50+
const serializedQuery = type === 'query' ?
51+
buildGraphqlQuery(schema, {
5252
operationName: options.operationName,
5353
variableDefinitions
54-
})
55-
: buildGraphqlMutation(schema, {
54+
}) :
55+
buildGraphqlMutation(schema, {
5656
operationName: options.operationName,
5757
variableDefinitions
5858
});

source/zod-graphql-query-builder/builder.test.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ function checkQuery(testCase: QueryTestCase): TestFn {
5050
const builder = createQueryBuilder();
5151
const schema = buildSchema(builder);
5252

53-
const result = testCase.type === 'query'
54-
? builder.buildQuery(schema, operationOptions)
55-
: builder.buildMutation(schema, operationOptions);
53+
const result = testCase.type === 'query' ?
54+
builder.buildQuery(schema, operationOptions) :
55+
builder.buildMutation(schema, operationOptions);
5656

5757
assert.strictEqual(result, expectedQuery);
5858
};
@@ -652,6 +652,28 @@ function checkQuery(testCase: QueryTestCase): TestFn {
652652
})
653653
);
654654

655+
test(
656+
`builds a ${operationType} with readonly objects`,
657+
checkQuery({
658+
type: operationType,
659+
buildSchema() {
660+
return z.object({ foo: z.string() }).strict().readonly();
661+
},
662+
expectedQuery: `${operationType} { foo }`
663+
})
664+
);
665+
666+
test(
667+
`builds a ${operationType} with nested readonly objects`,
668+
checkQuery({
669+
type: operationType,
670+
buildSchema() {
671+
return z.object({ foo: z.object({ bar: z.string() }).strict().readonly() }).strict().readonly();
672+
},
673+
expectedQuery: `${operationType} { foo { bar } }`
674+
})
675+
);
676+
655677
test(
656678
`builds a ${operationType} with union of primitives fields`,
657679
checkQuery({

source/zod-graphql-query-builder/builder.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { type ArrayCardinality, z, ZodArray, ZodDiscriminatedUnion, type ZodLazy, ZodUndefined } from 'zod';
1+
import {
2+
type ArrayCardinality,
3+
z,
4+
ZodArray,
5+
ZodDiscriminatedUnion,
6+
type ZodLazy,
7+
ZodReadonly,
8+
ZodUndefined
9+
} from 'zod';
210
import { isCustomScalarSchema } from './custom-scalar.js';
311
import {
412
type FieldSchema,
@@ -229,8 +237,9 @@ export function createQueryBuilder(): QueryBuilder {
229237
let referencedVariables = new Set<string>();
230238
const { variableDefinitions = {}, operationName = '' } = options;
231239
const bodyEntries: string[] = [];
240+
const shape = schema instanceof ZodReadonly ? schema.unwrap().shape : schema.shape;
232241

233-
for (const [fieldName, fieldSchema] of Object.entries(schema.shape)) {
242+
for (const [fieldName, fieldSchema] of Object.entries(shape)) {
234243
const serializedField = serializeFieldSchema(fieldName, fieldSchema);
235244

236245
if (serializedField.serializedValue.length > 0) {

source/zod-graphql-query-builder/query-schema.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
type ZodNumber,
1212
ZodObject,
1313
type ZodRawShape,
14-
type ZodReadonly,
14+
ZodReadonly,
1515
type ZodString,
1616
ZodTuple,
1717
type ZodTypeAny,
@@ -66,14 +66,16 @@ function isWrappedFieldSchema(schema: FieldSchema): schema is WrappedFieldSchema
6666
return false;
6767
}
6868

69-
return schema instanceof ZodLazy || schema instanceof ZodEffects || schema instanceof ZodNullable;
69+
return schema instanceof ZodLazy || schema instanceof ZodEffects || schema instanceof ZodNullable ||
70+
schema instanceof ZodReadonly;
7071
}
7172

7273
type UnwrappedChainResult = {
7374
unwrappedSchema: NonWrappedFieldSchema;
7475
wrapperElements: WrappedFieldSchema[];
7576
};
7677

78+
// eslint-disable-next-line max-statements,complexity -- no idea how to refactor for now
7779
function recursiveUnwrapFieldSchemaChain(
7880
parent: FieldSchema,
7981
currentChain: WrappedFieldSchema[]
@@ -93,6 +95,8 @@ function recursiveUnwrapFieldSchemaChain(
9395
unwrapped = parent.innerType();
9496
} else if (parent instanceof ZodNullable) {
9597
unwrapped = parent.unwrap();
98+
} else if (parent instanceof ZodReadonly) {
99+
unwrapped = parent.unwrap();
96100
}
97101

98102
if (isWrappedFieldSchema(unwrapped)) {
@@ -115,7 +119,7 @@ export function unwrapFieldSchema(parent: FieldSchema): NonWrappedFieldSchema {
115119
}
116120

117121
type QueryShape = Record<string, FieldSchema>;
118-
export type QuerySchema = StrictObjectSchema<QueryShape>;
122+
export type QuerySchema = StrictObjectSchema<QueryShape> | ZodReadonly<StrictObjectSchema<QueryShape>>;
119123

120124
export type FieldSchemaTuple<Schema extends FieldSchema> = ZodTuple<[Schema, ...Schema[]], Schema | null>;
121125

0 commit comments

Comments
 (0)