@gqlkit-ts/cli 0.0.1 → 0.1.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/LICENSE +21 -0
- package/dist/auto-type-generator/auto-type-generator.d.ts +46 -0
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/auto-type-generator.js +353 -0
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -0
- package/dist/auto-type-generator/auto-type-generator.test.d.ts +2 -0
- package/dist/auto-type-generator/auto-type-generator.test.d.ts.map +1 -0
- package/dist/auto-type-generator/auto-type-generator.test.js +613 -0
- package/dist/auto-type-generator/auto-type-generator.test.js.map +1 -0
- package/dist/auto-type-generator/index.d.ts +4 -0
- package/dist/auto-type-generator/index.d.ts.map +1 -0
- package/dist/auto-type-generator/index.js +3 -0
- package/dist/auto-type-generator/index.js.map +1 -0
- package/dist/auto-type-generator/name-collision-validator.d.ts +17 -0
- package/dist/auto-type-generator/name-collision-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/name-collision-validator.js +68 -0
- package/dist/auto-type-generator/name-collision-validator.js.map +1 -0
- package/dist/auto-type-generator/name-collision-validator.test.d.ts +2 -0
- package/dist/auto-type-generator/name-collision-validator.test.d.ts.map +1 -0
- package/dist/auto-type-generator/name-collision-validator.test.js +358 -0
- package/dist/auto-type-generator/name-collision-validator.test.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.d.ts +40 -0
- package/dist/auto-type-generator/naming-convention.d.ts.map +1 -0
- package/dist/auto-type-generator/naming-convention.js +59 -0
- package/dist/auto-type-generator/naming-convention.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.test.d.ts +2 -0
- package/dist/auto-type-generator/naming-convention.test.d.ts.map +1 -0
- package/dist/auto-type-generator/naming-convention.test.js +132 -0
- package/dist/auto-type-generator/naming-convention.test.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/gen.d.ts +32 -0
- package/dist/commands/gen.d.ts.map +1 -0
- package/dist/commands/gen.js +101 -0
- package/dist/commands/gen.js.map +1 -0
- package/dist/commands/gen.test.d.ts +2 -0
- package/dist/commands/gen.test.d.ts.map +1 -0
- package/dist/commands/gen.test.js +226 -0
- package/dist/commands/gen.test.js.map +1 -0
- package/dist/commands/main.d.ts +12 -0
- package/dist/commands/main.d.ts.map +1 -0
- package/dist/commands/main.js +5 -0
- package/dist/commands/main.js.map +1 -0
- package/dist/config/define-config.d.ts +26 -0
- package/dist/config/define-config.d.ts.map +1 -0
- package/dist/config/define-config.js +27 -0
- package/dist/config/define-config.js.map +1 -0
- package/dist/config/index.d.ts +3 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +131 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/config-loader/index.d.ts +3 -0
- package/dist/config-loader/index.d.ts.map +1 -0
- package/dist/config-loader/index.js +2 -0
- package/dist/config-loader/index.js.map +1 -0
- package/dist/config-loader/loader.d.ts +50 -0
- package/dist/config-loader/loader.d.ts.map +1 -0
- package/dist/config-loader/loader.js +78 -0
- package/dist/config-loader/loader.js.map +1 -0
- package/dist/config-loader/loader.test.d.ts +2 -0
- package/dist/config-loader/loader.test.d.ts.map +1 -0
- package/dist/config-loader/loader.test.js +123 -0
- package/dist/config-loader/loader.test.js.map +1 -0
- package/dist/config-loader/validator.d.ts +13 -0
- package/dist/config-loader/validator.d.ts.map +1 -0
- package/dist/config-loader/validator.js +497 -0
- package/dist/config-loader/validator.js.map +1 -0
- package/dist/config-loader/validator.test.d.ts +2 -0
- package/dist/config-loader/validator.test.d.ts.map +1 -0
- package/dist/config-loader/validator.test.js +846 -0
- package/dist/config-loader/validator.test.js.map +1 -0
- package/dist/gen-orchestrator/golden.test.d.ts +2 -0
- package/dist/gen-orchestrator/golden.test.d.ts.map +1 -0
- package/dist/gen-orchestrator/golden.test.js +102 -0
- package/dist/gen-orchestrator/golden.test.js.map +1 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.d.ts +25 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.d.ts.map +1 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.js +68 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.js.map +1 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts +2 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts.map +1 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.js +167 -0
- package/dist/gen-orchestrator/hook-executor/hook-executor.test.js.map +1 -0
- package/dist/gen-orchestrator/orchestrator.d.ts +30 -0
- package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -0
- package/dist/gen-orchestrator/orchestrator.js +407 -0
- package/dist/gen-orchestrator/orchestrator.js.map +1 -0
- package/dist/gen-orchestrator/reporter/diagnostic-reporter.d.ts +9 -0
- package/dist/gen-orchestrator/reporter/diagnostic-reporter.d.ts.map +1 -0
- package/dist/gen-orchestrator/reporter/diagnostic-reporter.js +32 -0
- package/dist/gen-orchestrator/reporter/diagnostic-reporter.js.map +1 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.d.ts +19 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.d.ts.map +1 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.js +38 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.js.map +1 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts +2 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts.map +1 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.test.js +74 -0
- package/dist/gen-orchestrator/reporter/progress-reporter.test.js.map +1 -0
- package/dist/gen-orchestrator/writer/file-writer.d.ts +13 -0
- package/dist/gen-orchestrator/writer/file-writer.d.ts.map +1 -0
- package/dist/gen-orchestrator/writer/file-writer.js +22 -0
- package/dist/gen-orchestrator/writer/file-writer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/resolver-extractor/extract-resolvers.d.ts +40 -0
- package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -0
- package/dist/resolver-extractor/extract-resolvers.js +2 -0
- package/dist/resolver-extractor/extract-resolvers.js.map +1 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +50 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.js +685 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -0
- package/dist/resolver-extractor/index.d.ts +5 -0
- package/dist/resolver-extractor/index.d.ts.map +1 -0
- package/dist/resolver-extractor/index.js +2 -0
- package/dist/resolver-extractor/index.js.map +1 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +25 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js +172 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -0
- package/dist/resolver-extractor/validator/only-validator.d.ts +61 -0
- package/dist/resolver-extractor/validator/only-validator.d.ts.map +1 -0
- package/dist/resolver-extractor/validator/only-validator.js +76 -0
- package/dist/resolver-extractor/validator/only-validator.js.map +1 -0
- package/dist/resolver-extractor/validator/only-validator.test.d.ts +8 -0
- package/dist/resolver-extractor/validator/only-validator.test.d.ts.map +1 -0
- package/dist/resolver-extractor/validator/only-validator.test.js +352 -0
- package/dist/resolver-extractor/validator/only-validator.test.js.map +1 -0
- package/dist/schema-generator/builder/ast-builder.d.ts +7 -0
- package/dist/schema-generator/builder/ast-builder.d.ts.map +1 -0
- package/dist/schema-generator/builder/ast-builder.js +417 -0
- package/dist/schema-generator/builder/ast-builder.js.map +1 -0
- package/dist/schema-generator/builder/ast-builder.test.d.ts +2 -0
- package/dist/schema-generator/builder/ast-builder.test.d.ts.map +1 -0
- package/dist/schema-generator/builder/ast-builder.test.js +469 -0
- package/dist/schema-generator/builder/ast-builder.test.js.map +1 -0
- package/dist/schema-generator/emitter/code-emitter.d.ts +7 -0
- package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -0
- package/dist/schema-generator/emitter/code-emitter.js +201 -0
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -0
- package/dist/schema-generator/emitter/sdl-emitter.d.ts +7 -0
- package/dist/schema-generator/emitter/sdl-emitter.d.ts.map +1 -0
- package/dist/schema-generator/emitter/sdl-emitter.js +11 -0
- package/dist/schema-generator/emitter/sdl-emitter.js.map +1 -0
- package/dist/schema-generator/generate-schema.d.ts +26 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -0
- package/dist/schema-generator/generate-schema.js +76 -0
- package/dist/schema-generator/generate-schema.js.map +1 -0
- package/dist/schema-generator/index.d.ts +4 -0
- package/dist/schema-generator/index.d.ts.map +1 -0
- package/dist/schema-generator/index.js +2 -0
- package/dist/schema-generator/index.js.map +1 -0
- package/dist/schema-generator/integrator/result-integrator.d.ts +93 -0
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -0
- package/dist/schema-generator/integrator/result-integrator.js +396 -0
- package/dist/schema-generator/integrator/result-integrator.js.map +1 -0
- package/dist/schema-generator/pruner/schema-pruner.d.ts +16 -0
- package/dist/schema-generator/pruner/schema-pruner.d.ts.map +1 -0
- package/dist/schema-generator/pruner/schema-pruner.js +66 -0
- package/dist/schema-generator/pruner/schema-pruner.js.map +1 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +24 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js +61 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -0
- package/dist/shared/constants.d.ts +70 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +128 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/default-value-detector.d.ts +40 -0
- package/dist/shared/default-value-detector.d.ts.map +1 -0
- package/dist/shared/default-value-detector.js +124 -0
- package/dist/shared/default-value-detector.js.map +1 -0
- package/dist/shared/diagnostics.d.ts +4 -0
- package/dist/shared/diagnostics.d.ts.map +1 -0
- package/dist/shared/diagnostics.js +25 -0
- package/dist/shared/diagnostics.js.map +1 -0
- package/dist/shared/directive-definition-extractor.d.ts +64 -0
- package/dist/shared/directive-definition-extractor.d.ts.map +1 -0
- package/dist/shared/directive-definition-extractor.js +399 -0
- package/dist/shared/directive-definition-extractor.js.map +1 -0
- package/dist/shared/directive-detector.d.ts +102 -0
- package/dist/shared/directive-detector.d.ts.map +1 -0
- package/dist/shared/directive-detector.js +422 -0
- package/dist/shared/directive-detector.js.map +1 -0
- package/dist/shared/file-scanner.d.ts +25 -0
- package/dist/shared/file-scanner.d.ts.map +1 -0
- package/dist/shared/file-scanner.js +99 -0
- package/dist/shared/file-scanner.js.map +1 -0
- package/dist/shared/file-scanner.test.d.ts +2 -0
- package/dist/shared/file-scanner.test.d.ts.map +1 -0
- package/dist/shared/file-scanner.test.js +138 -0
- package/dist/shared/file-scanner.test.js.map +1 -0
- package/dist/shared/index.d.ts +10 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +8 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/shared/inline-object-extractor.d.ts +13 -0
- package/dist/shared/inline-object-extractor.d.ts.map +1 -0
- package/dist/shared/inline-object-extractor.js +65 -0
- package/dist/shared/inline-object-extractor.js.map +1 -0
- package/dist/shared/inline-object-utils.d.ts +7 -0
- package/dist/shared/inline-object-utils.d.ts.map +1 -0
- package/dist/shared/inline-object-utils.js +23 -0
- package/dist/shared/inline-object-utils.js.map +1 -0
- package/dist/shared/interface-detector.d.ts +22 -0
- package/dist/shared/interface-detector.d.ts.map +1 -0
- package/dist/shared/interface-detector.js +90 -0
- package/dist/shared/interface-detector.js.map +1 -0
- package/dist/shared/interface-validator.d.ts +9 -0
- package/dist/shared/interface-validator.d.ts.map +1 -0
- package/dist/shared/interface-validator.js +152 -0
- package/dist/shared/interface-validator.js.map +1 -0
- package/dist/shared/interface-validator.test.d.ts +2 -0
- package/dist/shared/interface-validator.test.d.ts.map +1 -0
- package/dist/shared/interface-validator.test.js +145 -0
- package/dist/shared/interface-validator.test.js.map +1 -0
- package/dist/shared/metadata-detector.d.ts +65 -0
- package/dist/shared/metadata-detector.d.ts.map +1 -0
- package/dist/shared/metadata-detector.js +333 -0
- package/dist/shared/metadata-detector.js.map +1 -0
- package/dist/shared/program-factory.d.ts +14 -0
- package/dist/shared/program-factory.d.ts.map +1 -0
- package/dist/shared/program-factory.js +29 -0
- package/dist/shared/program-factory.js.map +1 -0
- package/dist/shared/source-location.d.ts +11 -0
- package/dist/shared/source-location.d.ts.map +1 -0
- package/dist/shared/source-location.js +15 -0
- package/dist/shared/source-location.js.map +1 -0
- package/dist/shared/tsconfig-loader.d.ts +13 -0
- package/dist/shared/tsconfig-loader.d.ts.map +1 -0
- package/dist/shared/tsconfig-loader.js +90 -0
- package/dist/shared/tsconfig-loader.js.map +1 -0
- package/dist/shared/tsdoc-parser.d.ts +12 -0
- package/dist/shared/tsdoc-parser.d.ts.map +1 -0
- package/dist/shared/tsdoc-parser.js +101 -0
- package/dist/shared/tsdoc-parser.js.map +1 -0
- package/dist/shared/type-converter.d.ts +3 -0
- package/dist/shared/type-converter.d.ts.map +1 -0
- package/dist/shared/type-converter.js +72 -0
- package/dist/shared/type-converter.js.map +1 -0
- package/dist/shared/typescript-utils.d.ts +55 -0
- package/dist/shared/typescript-utils.d.ts.map +1 -0
- package/dist/shared/typescript-utils.js +149 -0
- package/dist/shared/typescript-utils.js.map +1 -0
- package/dist/type-extractor/collector/result-collector.d.ts +7 -0
- package/dist/type-extractor/collector/result-collector.d.ts.map +1 -0
- package/dist/type-extractor/collector/result-collector.js +35 -0
- package/dist/type-extractor/collector/result-collector.js.map +1 -0
- package/dist/type-extractor/collector/scalar-collector.d.ts +108 -0
- package/dist/type-extractor/collector/scalar-collector.d.ts.map +1 -0
- package/dist/type-extractor/collector/scalar-collector.js +133 -0
- package/dist/type-extractor/collector/scalar-collector.js.map +1 -0
- package/dist/type-extractor/converter/field-eligibility.d.ts +34 -0
- package/dist/type-extractor/converter/field-eligibility.d.ts.map +1 -0
- package/dist/type-extractor/converter/field-eligibility.js +89 -0
- package/dist/type-extractor/converter/field-eligibility.js.map +1 -0
- package/dist/type-extractor/converter/graphql-converter.d.ts +7 -0
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -0
- package/dist/type-extractor/converter/graphql-converter.js +299 -0
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -0
- package/dist/type-extractor/extract-types.d.ts +2 -0
- package/dist/type-extractor/extract-types.d.ts.map +1 -0
- package/dist/type-extractor/extract-types.js +2 -0
- package/dist/type-extractor/extract-types.js.map +1 -0
- package/dist/type-extractor/extractor/type-extractor.d.ts +27 -0
- package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -0
- package/dist/type-extractor/extractor/type-extractor.js +1116 -0
- package/dist/type-extractor/extractor/type-extractor.js.map +1 -0
- package/dist/type-extractor/index.d.ts +4 -0
- package/dist/type-extractor/index.d.ts.map +1 -0
- package/dist/type-extractor/index.js +2 -0
- package/dist/type-extractor/index.js.map +1 -0
- package/dist/type-extractor/types/diagnostics.d.ts +17 -0
- package/dist/type-extractor/types/diagnostics.d.ts.map +1 -0
- package/dist/type-extractor/types/diagnostics.js +2 -0
- package/dist/type-extractor/types/diagnostics.js.map +1 -0
- package/dist/type-extractor/types/graphql.d.ts +40 -0
- package/dist/type-extractor/types/graphql.d.ts.map +1 -0
- package/dist/type-extractor/types/graphql.js +2 -0
- package/dist/type-extractor/types/graphql.js.map +1 -0
- package/dist/type-extractor/types/index.d.ts +5 -0
- package/dist/type-extractor/types/index.d.ts.map +1 -0
- package/dist/type-extractor/types/index.js +2 -0
- package/dist/type-extractor/types/index.js.map +1 -0
- package/dist/type-extractor/types/typescript.d.ts +86 -0
- package/dist/type-extractor/types/typescript.d.ts.map +1 -0
- package/dist/type-extractor/types/typescript.js +2 -0
- package/dist/type-extractor/types/typescript.js.map +1 -0
- package/dist/type-extractor/types/typescript.test.d.ts +2 -0
- package/dist/type-extractor/types/typescript.test.d.ts.map +1 -0
- package/dist/type-extractor/types/typescript.test.js +287 -0
- package/dist/type-extractor/types/typescript.test.js.map +1 -0
- package/dist/type-extractor/validator/type-validator.d.ts +11 -0
- package/dist/type-extractor/validator/type-validator.d.ts.map +1 -0
- package/dist/type-extractor/validator/type-validator.js +53 -0
- package/dist/type-extractor/validator/type-validator.js.map +1 -0
- package/docs/configuration.md +163 -0
- package/docs/getting-started.md +117 -0
- package/docs/index.md +32 -0
- package/docs/integration/apollo.md +109 -0
- package/docs/integration/yoga.md +108 -0
- package/docs/schema/abstract-resolvers.md +146 -0
- package/docs/schema/directives.md +196 -0
- package/docs/schema/documentation.md +176 -0
- package/docs/schema/enums.md +162 -0
- package/docs/schema/fields.md +184 -0
- package/docs/schema/index.md +38 -0
- package/docs/schema/inputs.md +277 -0
- package/docs/schema/interfaces.md +178 -0
- package/docs/schema/objects.md +186 -0
- package/docs/schema/queries-mutations.md +205 -0
- package/docs/schema/scalars.md +194 -0
- package/docs/schema/unions.md +90 -0
- package/docs/what-is-gqlkit.md +22 -0
- package/package.json +59 -7
- package/README.md +0 -45
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Field Resolvers
|
|
2
|
+
|
|
3
|
+
Add computed fields to object types using `defineField`. Define them alongside the type.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// src/gqlkit/schema/user.ts
|
|
9
|
+
import { defineField } from "../gqlkit";
|
|
10
|
+
import type { IDString, NoArgs } from "@gqlkit-ts/runtime";
|
|
11
|
+
import type { Post } from "./post.js";
|
|
12
|
+
|
|
13
|
+
export type User = {
|
|
14
|
+
id: IDString;
|
|
15
|
+
name: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** Get posts authored by this user */
|
|
19
|
+
export const posts = defineField<User, NoArgs, Post[]>(
|
|
20
|
+
(parent) => findPostsByAuthor(parent.id)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
/** Get user's post count */
|
|
24
|
+
export const postCount = defineField<User, NoArgs, number>(
|
|
25
|
+
(parent) => countPostsByAuthor(parent.id)
|
|
26
|
+
);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Generates:
|
|
30
|
+
|
|
31
|
+
```graphql
|
|
32
|
+
type User {
|
|
33
|
+
id: ID!
|
|
34
|
+
name: String!
|
|
35
|
+
"""Get posts authored by this user"""
|
|
36
|
+
posts: [Post!]!
|
|
37
|
+
"""Get user's post count"""
|
|
38
|
+
postCount: Float!
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Resolver Function Signature
|
|
43
|
+
|
|
44
|
+
Field resolvers receive four arguments:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
(parent, args, ctx, info) => ReturnType
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
| Argument | Description |
|
|
51
|
+
|----------|-------------|
|
|
52
|
+
| `parent` | The parent object (typed via the first type parameter) |
|
|
53
|
+
| `args` | The arguments passed to the field |
|
|
54
|
+
| `ctx` | The context object (typed via `gqlkit.ts`) |
|
|
55
|
+
| `info` | GraphQL resolve info |
|
|
56
|
+
|
|
57
|
+
## Type Parameters
|
|
58
|
+
|
|
59
|
+
`defineField<TParent, TArgs, TResult>`:
|
|
60
|
+
|
|
61
|
+
| Parameter | Description |
|
|
62
|
+
|-----------|-------------|
|
|
63
|
+
| `TParent` | The parent object type this field is defined on |
|
|
64
|
+
| `TArgs` | The arguments type (use `NoArgs` if no arguments) |
|
|
65
|
+
| `TResult` | The return type of the field |
|
|
66
|
+
|
|
67
|
+
## Fields with Arguments
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
export const posts = defineField<
|
|
71
|
+
User,
|
|
72
|
+
{ limit: number; offset: number },
|
|
73
|
+
Post[]
|
|
74
|
+
>((parent, args) => {
|
|
75
|
+
return findPostsByAuthor(parent.id, args.limit, args.offset);
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Generates:
|
|
80
|
+
|
|
81
|
+
```graphql
|
|
82
|
+
type User {
|
|
83
|
+
posts(limit: Float!, offset: Float!): [Post!]!
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Inline Object Arguments
|
|
88
|
+
|
|
89
|
+
Field resolver arguments can use inline object literals. gqlkit automatically generates Input Object types with the naming convention `{ParentTypeName}{PascalCaseFieldName}{PascalCaseArgName}Input`:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { defineField } from "../gqlkit";
|
|
93
|
+
|
|
94
|
+
export const posts = defineField<
|
|
95
|
+
User,
|
|
96
|
+
{
|
|
97
|
+
/** Filter options */
|
|
98
|
+
filter: {
|
|
99
|
+
titlePattern: string | null;
|
|
100
|
+
status: PostStatus | null;
|
|
101
|
+
} | null;
|
|
102
|
+
},
|
|
103
|
+
Post[]
|
|
104
|
+
>((parent, args) => []);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Generates:
|
|
108
|
+
|
|
109
|
+
```graphql
|
|
110
|
+
type User {
|
|
111
|
+
posts(
|
|
112
|
+
"""Filter options"""
|
|
113
|
+
filter: UserPostsFilterInput
|
|
114
|
+
): [Post!]!
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
input UserPostsFilterInput {
|
|
118
|
+
titlePattern: String
|
|
119
|
+
status: PostStatus
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Default Values in Arguments
|
|
124
|
+
|
|
125
|
+
Default values in Input Objects are applied to resolver arguments:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { defineQuery } from "../gqlkit";
|
|
129
|
+
import type { GqlField, Int } from "@gqlkit-ts/runtime";
|
|
130
|
+
|
|
131
|
+
export type PaginationInput = {
|
|
132
|
+
limit: GqlField<Int, { defaultValue: 10 }>;
|
|
133
|
+
offset: GqlField<Int, { defaultValue: 0 }>;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export type User = {
|
|
137
|
+
id: string;
|
|
138
|
+
name: string;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
export const users = defineQuery<PaginationInput, User[]>(() => []);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Generates:
|
|
145
|
+
|
|
146
|
+
```graphql
|
|
147
|
+
type Query {
|
|
148
|
+
users(limit: Int! = 10, offset: Int! = 0): [User!]!
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Interface Field Resolvers
|
|
153
|
+
|
|
154
|
+
Add computed fields to interface types using `defineField`:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { defineField } from "../gqlkit";
|
|
158
|
+
import type { NoArgs } from "@gqlkit-ts/runtime";
|
|
159
|
+
import type { Node } from "./node.js";
|
|
160
|
+
|
|
161
|
+
/** Get the typename of a Node */
|
|
162
|
+
export const __typename = defineField<Node, NoArgs, string>(
|
|
163
|
+
(parent) => parent.constructor.name
|
|
164
|
+
);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Attaching Directives
|
|
168
|
+
|
|
169
|
+
Add a fourth type parameter to attach directives to field resolvers:
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
import { defineField } from "../gqlkit";
|
|
173
|
+
import type { NoArgs } from "@gqlkit-ts/runtime";
|
|
174
|
+
import { type AuthDirective } from "./directives.js";
|
|
175
|
+
|
|
176
|
+
export const email = defineField<
|
|
177
|
+
User,
|
|
178
|
+
NoArgs,
|
|
179
|
+
string,
|
|
180
|
+
[AuthDirective<{ role: ["ADMIN"] }>]
|
|
181
|
+
>((parent) => parent.email);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
See [Directives](./directives.md) for more details on defining and using custom directives.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Schema Definition
|
|
2
|
+
|
|
3
|
+
gqlkit generates GraphQL schema from your TypeScript types. All exported types from `src/gqlkit/schema/` are automatically scanned and converted to GraphQL types.
|
|
4
|
+
|
|
5
|
+
## Type Mapping
|
|
6
|
+
|
|
7
|
+
gqlkit maps TypeScript types to GraphQL types as follows:
|
|
8
|
+
|
|
9
|
+
| TypeScript | GraphQL |
|
|
10
|
+
|------------|---------|
|
|
11
|
+
| `string` | `String!` |
|
|
12
|
+
| `number` | `Float!` |
|
|
13
|
+
| `boolean` | `Boolean!` |
|
|
14
|
+
| `IDString`, `IDNumber` | `ID!` |
|
|
15
|
+
| `Int` (branded) | `Int!` |
|
|
16
|
+
| `Float` (branded) | `Float!` |
|
|
17
|
+
| `T \| null` | `T` (nullable) |
|
|
18
|
+
| `T[]` | `[T!]!` |
|
|
19
|
+
| String literal union | Enum type |
|
|
20
|
+
| TypeScript `enum` | Enum type |
|
|
21
|
+
| Union of object types | Union type |
|
|
22
|
+
| `*Input` suffix types | Input Object type |
|
|
23
|
+
| Union with `*Input` suffix | `@oneOf` input object |
|
|
24
|
+
| `GqlInterface<T>` | Interface type |
|
|
25
|
+
| `GqlScalar<Name, Base>` | Custom scalar |
|
|
26
|
+
|
|
27
|
+
## Project Layout
|
|
28
|
+
|
|
29
|
+
Default project layout:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
src/
|
|
33
|
+
gqlkit/
|
|
34
|
+
schema/ # Types and resolvers co-located
|
|
35
|
+
__generated__/ # Generated files (auto-created)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
All TypeScript files (`.ts`, `.cts`, `.mts`) under `src/gqlkit/schema/` are scanned for types and resolvers.
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Input Types
|
|
2
|
+
|
|
3
|
+
TypeScript types with `Input` suffix are treated as GraphQL input types.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
/** Input for creating a new user */
|
|
9
|
+
export interface CreateUserInput {
|
|
10
|
+
name: string;
|
|
11
|
+
email: string | null;
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Generates:
|
|
16
|
+
|
|
17
|
+
```graphql
|
|
18
|
+
"""Input for creating a new user"""
|
|
19
|
+
input CreateUserInput {
|
|
20
|
+
name: String!
|
|
21
|
+
email: String
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Inline Objects
|
|
26
|
+
|
|
27
|
+
Input types can use inline object literals for nested structures. gqlkit automatically generates Input Object types with the naming convention `{ParentTypeNameWithoutInputSuffix}{PascalCaseFieldName}Input`:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import type { GqlField, Int } from "@gqlkit-ts/runtime";
|
|
31
|
+
|
|
32
|
+
export type CreateUserInput = {
|
|
33
|
+
name: string;
|
|
34
|
+
/** Profile information */
|
|
35
|
+
profile: {
|
|
36
|
+
bio: string | null;
|
|
37
|
+
/** User's age with default value */
|
|
38
|
+
age: GqlField<Int | null, { defaultValue: 18 }>;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Generates:
|
|
44
|
+
|
|
45
|
+
```graphql
|
|
46
|
+
input CreateUserInput {
|
|
47
|
+
name: String!
|
|
48
|
+
"""Profile information"""
|
|
49
|
+
profile: CreateUserProfileInput!
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
input CreateUserProfileInput {
|
|
53
|
+
"""User's age with default value"""
|
|
54
|
+
age: Int = 18
|
|
55
|
+
bio: String
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Nested inline objects generate types with concatenated names (e.g., `UserProfileInput.address` → `UserProfileAddressInput`).
|
|
60
|
+
|
|
61
|
+
## @oneOf Input Objects
|
|
62
|
+
|
|
63
|
+
Union types with `Input` suffix using inline object literals generate `@oneOf` input objects. Each union member must be an inline object literal with exactly one property. Property values can be scalar types, enum types, or references to Input Object types:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
/**
|
|
67
|
+
* Specifies how to identify a product.
|
|
68
|
+
* Exactly one field must be provided.
|
|
69
|
+
*/
|
|
70
|
+
export type ProductInput =
|
|
71
|
+
| { id: string }
|
|
72
|
+
| { name: string }
|
|
73
|
+
| { location: LocationInput };
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Generates:
|
|
77
|
+
|
|
78
|
+
```graphql
|
|
79
|
+
"""
|
|
80
|
+
Specifies how to identify a product.
|
|
81
|
+
Exactly one field must be provided.
|
|
82
|
+
"""
|
|
83
|
+
input ProductInput @oneOf {
|
|
84
|
+
id: String
|
|
85
|
+
location: LocationInput
|
|
86
|
+
name: String
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Each property becomes a nullable field in the generated input type. The `@oneOf` directive ensures exactly one field is provided at runtime.
|
|
91
|
+
|
|
92
|
+
## Default Values
|
|
93
|
+
|
|
94
|
+
Specify default values for Input Object fields using `GqlField` with the `defaultValue` option.
|
|
95
|
+
|
|
96
|
+
### Basic Default Values
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { type GqlField, type Int } from "@gqlkit-ts/runtime";
|
|
100
|
+
|
|
101
|
+
export type PaginationInput = {
|
|
102
|
+
limit: GqlField<Int, { defaultValue: 10 }>;
|
|
103
|
+
offset: GqlField<Int, { defaultValue: 0 }>;
|
|
104
|
+
includeArchived: GqlField<boolean, { defaultValue: false }>;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export type SearchInput = {
|
|
108
|
+
query: string;
|
|
109
|
+
caseSensitive: GqlField<boolean, { defaultValue: true }>;
|
|
110
|
+
maxResults: GqlField<Int | null, { defaultValue: null }>;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export type GreetingInput = {
|
|
114
|
+
name: GqlField<string, { defaultValue: "World" }>;
|
|
115
|
+
prefix: GqlField<string, { defaultValue: "Hello" }>;
|
|
116
|
+
};
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Generates:
|
|
120
|
+
|
|
121
|
+
```graphql
|
|
122
|
+
input PaginationInput {
|
|
123
|
+
limit: Int! = 10
|
|
124
|
+
offset: Int! = 0
|
|
125
|
+
includeArchived: Boolean! = false
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
input SearchInput {
|
|
129
|
+
query: String!
|
|
130
|
+
caseSensitive: Boolean! = true
|
|
131
|
+
maxResults: Int = null
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
input GreetingInput {
|
|
135
|
+
name: String! = "World"
|
|
136
|
+
prefix: String! = "Hello"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Complex Default Values
|
|
141
|
+
|
|
142
|
+
Default values support arrays, objects, and enum values:
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
export type Status = "ACTIVE" | "INACTIVE" | "PENDING";
|
|
146
|
+
|
|
147
|
+
export type Priority = "LOW" | "MEDIUM" | "HIGH";
|
|
148
|
+
|
|
149
|
+
export type NestedConfig = {
|
|
150
|
+
enabled: boolean;
|
|
151
|
+
value: Int;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
export type FilterInput = {
|
|
155
|
+
status: GqlField<Status, { defaultValue: "ACTIVE" }>;
|
|
156
|
+
priorities: GqlField<Priority[], { defaultValue: ["MEDIUM", "HIGH"] }>;
|
|
157
|
+
tags: GqlField<string[], { defaultValue: ["default"] }>;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export type SettingsInput = {
|
|
161
|
+
config: GqlField<NestedConfig, { defaultValue: { enabled: true; value: 100 } }>;
|
|
162
|
+
limits: GqlField<Int[], { defaultValue: [10, 20, 30] }>;
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Generates:
|
|
167
|
+
|
|
168
|
+
```graphql
|
|
169
|
+
input FilterInput {
|
|
170
|
+
status: Status! = ACTIVE
|
|
171
|
+
priorities: [Priority!]! = [MEDIUM, HIGH]
|
|
172
|
+
tags: [String!]! = ["default"]
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
input SettingsInput {
|
|
176
|
+
config: NestedConfig! = {enabled: true, value: 100}
|
|
177
|
+
limits: [Int!]! = [10, 20, 30]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Default Values with Directives
|
|
182
|
+
|
|
183
|
+
You can combine `defaultValue` with `directives`:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
import { type GqlField, type GqlDirective, type Int } from "@gqlkit-ts/runtime";
|
|
187
|
+
|
|
188
|
+
export type LengthDirective<TArgs extends { min: number; max: number }> =
|
|
189
|
+
GqlDirective<"length", TArgs, "INPUT_FIELD_DEFINITION" | "ARGUMENT_DEFINITION">;
|
|
190
|
+
|
|
191
|
+
export type RangeDirective<TArgs extends { min: number; max: number }> =
|
|
192
|
+
GqlDirective<"range", TArgs, "INPUT_FIELD_DEFINITION" | "ARGUMENT_DEFINITION">;
|
|
193
|
+
|
|
194
|
+
export type CreateUserInput = {
|
|
195
|
+
name: GqlField<string, {
|
|
196
|
+
defaultValue: "Anonymous";
|
|
197
|
+
directives: [LengthDirective<{ min: 1; max: 100 }>];
|
|
198
|
+
}>;
|
|
199
|
+
age: GqlField<Int, {
|
|
200
|
+
defaultValue: 18;
|
|
201
|
+
directives: [RangeDirective<{ min: 0; max: 150 }>];
|
|
202
|
+
}>;
|
|
203
|
+
email: GqlField<string | null, {
|
|
204
|
+
defaultValue: null;
|
|
205
|
+
directives: [LengthDirective<{ min: 5; max: 255 }>];
|
|
206
|
+
}>;
|
|
207
|
+
};
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Generates:
|
|
211
|
+
|
|
212
|
+
```graphql
|
|
213
|
+
input CreateUserInput {
|
|
214
|
+
name: String! = "Anonymous" @length(min: 1, max: 100)
|
|
215
|
+
age: Int! = 18 @range(min: 0, max: 150)
|
|
216
|
+
email: String = null @length(min: 5, max: 255)
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Supported Default Value Types
|
|
221
|
+
|
|
222
|
+
| Value type | Example | GraphQL output |
|
|
223
|
+
|------------|---------|----------------|
|
|
224
|
+
| String | `"hello"` | `"hello"` |
|
|
225
|
+
| Number (Int) | `10` | `10` |
|
|
226
|
+
| Number (Float) | `3.14` | `3.14` |
|
|
227
|
+
| Boolean | `true`, `false` | `true`, `false` |
|
|
228
|
+
| Null | `null` | `null` |
|
|
229
|
+
| Array | `[1, 2, 3]` | `[1, 2, 3]` |
|
|
230
|
+
| Object | `{ key: "value" }` | `{key: "value"}` |
|
|
231
|
+
| Enum | `"ACTIVE"` (when field type is enum) | `ACTIVE` |
|
|
232
|
+
|
|
233
|
+
### Literal Types Required
|
|
234
|
+
|
|
235
|
+
Default values must be specified as TypeScript literal types. Non-literal types will cause a warning:
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// ✅ OK: Literal types
|
|
239
|
+
export type GoodInput = {
|
|
240
|
+
limit: GqlField<Int, { defaultValue: 10 }>;
|
|
241
|
+
name: GqlField<string, { defaultValue: "default" }>;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// ❌ Error: Non-literal types
|
|
245
|
+
export type BadInput = {
|
|
246
|
+
limit: GqlField<Int, { defaultValue: number }>; // Warning: must be literal
|
|
247
|
+
name: GqlField<string, { defaultValue: string }>; // Warning: must be literal
|
|
248
|
+
};
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Invalid Field Names
|
|
252
|
+
|
|
253
|
+
Input field names that are not valid GraphQL identifiers are automatically skipped with a warning. Valid GraphQL names must:
|
|
254
|
+
|
|
255
|
+
- Match the pattern `/^[_A-Za-z][_0-9A-Za-z]*$/`
|
|
256
|
+
- Not start with `__` (reserved for GraphQL introspection)
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
export type CreateUserInput = {
|
|
260
|
+
name: string; // ✅ Valid
|
|
261
|
+
_metadata: string; // ✅ Valid (single underscore is OK)
|
|
262
|
+
"123abc": string; // ⚠️ Skipped: starts with a number
|
|
263
|
+
__private: string; // ⚠️ Skipped: starts with __
|
|
264
|
+
"hyphen-field": string; // ⚠️ Skipped: contains hyphen
|
|
265
|
+
};
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Generates (invalid fields are skipped):
|
|
269
|
+
|
|
270
|
+
```graphql
|
|
271
|
+
input CreateUserInput {
|
|
272
|
+
name: String!
|
|
273
|
+
_metadata: String!
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
When fields are skipped, gqlkit outputs a warning with the field name and location.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Interface Types
|
|
2
|
+
|
|
3
|
+
Define GraphQL interface types using the `GqlInterface` utility type.
|
|
4
|
+
|
|
5
|
+
## Basic Usage
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// src/gqlkit/schema/node.ts
|
|
9
|
+
import { type GqlInterface, type IDString } from "@gqlkit-ts/runtime";
|
|
10
|
+
import type { DateTime } from "./scalars.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Node interface - represents any entity with a unique identifier.
|
|
14
|
+
*/
|
|
15
|
+
export type Node = GqlInterface<{
|
|
16
|
+
/** Global unique identifier */
|
|
17
|
+
id: IDString;
|
|
18
|
+
}>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Timestamped interface - entities that track creation time.
|
|
22
|
+
*/
|
|
23
|
+
export type Timestamped = GqlInterface<{
|
|
24
|
+
createdAt: DateTime;
|
|
25
|
+
}>;
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Generates:
|
|
29
|
+
|
|
30
|
+
```graphql
|
|
31
|
+
"""Node interface - represents any entity with a unique identifier."""
|
|
32
|
+
interface Node {
|
|
33
|
+
"""Global unique identifier"""
|
|
34
|
+
id: ID!
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
"""Timestamped interface - entities that track creation time."""
|
|
38
|
+
interface Timestamped {
|
|
39
|
+
createdAt: DateTime!
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## GqlInterface Type Parameters
|
|
44
|
+
|
|
45
|
+
`GqlInterface<T, Meta?>`:
|
|
46
|
+
|
|
47
|
+
| Parameter | Description |
|
|
48
|
+
|-----------|-------------|
|
|
49
|
+
| `T` | The interface fields definition |
|
|
50
|
+
| `Meta` | Optional: `{ implements: [...] }` for interface inheritance |
|
|
51
|
+
|
|
52
|
+
## Interface Inheritance
|
|
53
|
+
|
|
54
|
+
Interfaces can extend other interfaces:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
/**
|
|
58
|
+
* Entity interface - combines Node and Timestamped.
|
|
59
|
+
*/
|
|
60
|
+
export type Entity = GqlInterface<
|
|
61
|
+
{
|
|
62
|
+
id: IDString;
|
|
63
|
+
createdAt: DateTime;
|
|
64
|
+
},
|
|
65
|
+
{ implements: [Node, Timestamped] }
|
|
66
|
+
>;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Generates:
|
|
70
|
+
|
|
71
|
+
```graphql
|
|
72
|
+
"""Entity interface - combines Node and Timestamped."""
|
|
73
|
+
interface Entity implements Node & Timestamped {
|
|
74
|
+
id: ID!
|
|
75
|
+
createdAt: DateTime!
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Implementing Interfaces
|
|
80
|
+
|
|
81
|
+
Use `GqlObject` with the `implements` option to declare that a type implements interfaces:
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { type GqlObject, type IDString } from "@gqlkit-ts/runtime";
|
|
85
|
+
import type { Node, Timestamped } from "./node.js";
|
|
86
|
+
import type { DateTime } from "./scalars.js";
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* A user in the system.
|
|
90
|
+
*/
|
|
91
|
+
export type User = GqlObject<
|
|
92
|
+
{
|
|
93
|
+
id: IDString;
|
|
94
|
+
name: string;
|
|
95
|
+
email: string | null;
|
|
96
|
+
createdAt: DateTime;
|
|
97
|
+
},
|
|
98
|
+
{ implements: [Node, Timestamped] }
|
|
99
|
+
>;
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Generates:
|
|
103
|
+
|
|
104
|
+
```graphql
|
|
105
|
+
"""A user in the system."""
|
|
106
|
+
type User implements Node & Timestamped {
|
|
107
|
+
id: ID!
|
|
108
|
+
name: String!
|
|
109
|
+
email: String
|
|
110
|
+
createdAt: DateTime!
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Combining with Directives
|
|
115
|
+
|
|
116
|
+
You can combine `implements` with `directives`:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { type GqlObject, type IDString } from "@gqlkit-ts/runtime";
|
|
120
|
+
import type { Node, Timestamped } from "./node.js";
|
|
121
|
+
import type { DateTime } from "./scalars.js";
|
|
122
|
+
import type { CacheDirective } from "./directives.js";
|
|
123
|
+
|
|
124
|
+
export type Post = GqlObject<
|
|
125
|
+
{
|
|
126
|
+
id: IDString;
|
|
127
|
+
title: string;
|
|
128
|
+
createdAt: DateTime;
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
implements: [Node, Timestamped],
|
|
132
|
+
directives: [CacheDirective<{ maxAge: 60 }>]
|
|
133
|
+
}
|
|
134
|
+
>;
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Generates:
|
|
138
|
+
|
|
139
|
+
```graphql
|
|
140
|
+
type Post @cache(maxAge: 60) implements Node & Timestamped {
|
|
141
|
+
id: ID!
|
|
142
|
+
title: String!
|
|
143
|
+
createdAt: DateTime!
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Interface Field Resolvers
|
|
148
|
+
|
|
149
|
+
Add computed fields to interface types using `defineField`:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
import { defineField } from "../gqlkit";
|
|
153
|
+
import type { NoArgs } from "@gqlkit-ts/runtime";
|
|
154
|
+
import type { Node } from "./node.js";
|
|
155
|
+
|
|
156
|
+
/** Get the typename of a Node */
|
|
157
|
+
export const __typename = defineField<Node, NoArgs, string>(
|
|
158
|
+
(parent) => parent.constructor.name
|
|
159
|
+
);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
See [Object Types](./objects.md) for more details on implementing interfaces.
|
|
163
|
+
|
|
164
|
+
## Runtime Type Resolution
|
|
165
|
+
|
|
166
|
+
When GraphQL executes a query that returns an interface type, it needs to determine the concrete type at runtime. You can use either `defineResolveType` on the interface or `defineIsTypeOf` on each implementing type.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { defineResolveType } from "../gqlkit";
|
|
170
|
+
|
|
171
|
+
export const nodeResolveType = defineResolveType<Node>((value) => {
|
|
172
|
+
if ("name" in value) return "User";
|
|
173
|
+
if ("title" in value) return "Post";
|
|
174
|
+
throw new Error("Unknown Node type");
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
See [Abstract Type Resolution](./abstract-resolvers.md) for complete documentation.
|