Skip to content

Commit d7d5ecc

Browse files
committed
Support field calls in selection API
1 parent cfe5fb1 commit d7d5ecc

File tree

4 files changed

+47
-2
lines changed

4 files changed

+47
-2
lines changed

packages/core/spec/Select-type.spec.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { AssertTrue, IsExact } from "conditional-type-checks";
22
import type { DeepFilterNever, Select } from "../src/types.js";
3-
import type { TestSchema } from "./TestSchema.js";
3+
import { $args } from "../src/types.js";
4+
import type { TestSchema, TestSchemaWithFieldCalls } from "./TestSchema.js";
45

56
describe("Select<>", () => {
67
type _SelectingProperties = AssertTrue<IsExact<Select<TestSchema, { num: true }>, { num: number }>>;
@@ -75,5 +76,13 @@ describe("Select<>", () => {
7576
>
7677
>;
7778

79+
type _fieldCallSelection = Select<
80+
TestSchemaWithFieldCalls,
81+
{ fieldCall: { [$args]: { arg: [1, 2, 3]; limit: 10 }; nestedField1: true; nestedField2: { nestedField3: true } } }
82+
>;
83+
type _TestSelectingFieldCall = AssertTrue<
84+
IsExact<_fieldCallSelection, { fieldCall: { nestedField1: number; nestedField2: { nestedField3: string } } }>
85+
>;
86+
7887
test("true", () => undefined);
7988
});

packages/core/spec/TestSchema.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ export type NestedThing = {
77
nested: NestedThing;
88
};
99

10+
export type TestSchemaWithFieldCalls = {
11+
num: number;
12+
str: string;
13+
fieldCall: {
14+
nestedField1: number;
15+
nestedField2: {
16+
nestedField3: string;
17+
};
18+
};
19+
};
20+
1021
export type TestSchema = {
1122
num: number;
1223
str: string;

packages/core/src/AnyClient.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { AnyConnection } from "./AnyConnection.js";
22
import type { AnyCoreImplementation } from "./AnyCoreImplementation.js";
33
import type { AnyGadgetTransaction } from "./AnyGadgetTransaction.js";
44
import type { AnyInternalModelManager } from "./AnyInternalModelManager.js";
5+
import type { $args } from "./types.js";
56

67
export const $modelRelationships = Symbol.for("gadget/modelRelationships");
78
export const $coreImplementation = Symbol.for("gadget/coreImplementation");
@@ -22,4 +23,5 @@ export interface AnyClient {
2223
internal: InternalModelManagerNamespace;
2324
[$modelRelationships]?: { [modelName: string]: { [apiIdentifier: string]: { type: string; model: string } } };
2425
[$coreImplementation]?: AnyCoreImplementation;
26+
[$args]?: typeof $args;
2527
}

packages/core/src/types.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ type InnerSelect<Schema, Selection extends FieldSelection | null | undefined> =
115115
: Schema extends null
116116
? InnerSelect<Exclude<Schema, null>, Selection> | null
117117
: {
118-
[Key in keyof Selection & keyof Schema]: Selection[Key] extends true
118+
// Exclude the $args symbol key - it's for field arguments, not nested selections
119+
[Key in Exclude<keyof Selection, typeof $args> & keyof Schema]: Selection[Key] extends true
119120
? Schema[Key]
120121
: Selection[Key] extends FieldSelection
121122
? InnerSelect<Schema[Key], Selection[Key]>
@@ -989,10 +990,32 @@ export type ViewResult<F extends ViewFunction<any, any>> = Awaited<
989990
F extends ViewFunctionWithVariables<any, infer Result> ? Result : F extends ViewFunctionWithoutVariables<infer Result> ? Result : never
990991
>;
991992

993+
/**
994+
* Symbol key for field arguments in selections.
995+
* Using a symbol avoids conflicts with string index signatures.
996+
*/
997+
export const $args = Symbol.for("gadget/fieldArgs");
998+
999+
/**
1000+
* Type for field arguments (e.g., pagination, filtering on a field)
1001+
*/
1002+
export type FieldArgs = Record<string, any>;
1003+
9921004
/**
9931005
* Represents a list of fields selected from a GraphQL API call. Allows nesting, conditional selection.
9941006
* Example: `{ id: true, name: false, richText: { markdown: true, html: false } }`
1007+
*
1008+
* Supports field arguments using the $args symbol:
1009+
* ```
1010+
* {
1011+
* comments: {
1012+
* [$args]: { after: "cursor", first: 10 },
1013+
* body: true
1014+
* }
1015+
* }
1016+
* ```
9951017
**/
9961018
export interface FieldSelection {
1019+
[$args]?: FieldArgs;
9971020
[key: string]: boolean | null | undefined | FieldSelection;
9981021
}

0 commit comments

Comments
 (0)