Skip to content
This repository has been archived by the owner on Jul 20, 2023. It is now read-only.

Commit

Permalink
Support Client class codegen (#22)
Browse files Browse the repository at this point in the history
* Support Client class codegen

* Tweak Client base class

* Convert Client to interface for now
  • Loading branch information
timkendall committed Dec 26, 2020
1 parent 56dfb49 commit 88031b3
Show file tree
Hide file tree
Showing 5 changed files with 1,418 additions and 68 deletions.
137 changes: 137 additions & 0 deletions __tests__/starwars/starwars.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ import {
Selection,
SelectionSet,
Variable,
Executor,
Client,
} from "../../src";

export const VERSION = "unversioned";

export const SCHEMA_SHA = "4c13c55";

export enum Episode {
NEWHOPE = "NEWHOPE",
EMPIRE = "EMPIRE",
Expand Down Expand Up @@ -905,3 +911,134 @@ export const mutation = <T extends Array<Selection>>(
select: (t: typeof Mutation) => T
): Operation<SelectionSet<T>> =>
new Operation(name, "mutation", new SelectionSet(select(Mutation)));

export class Starwars implements Client {
public static readonly VERSION = VERSION;
public static readonly SCHEMA_SHA = SCHEMA_SHA;

constructor(public readonly executor: Executor) {}

public readonly query = {
hero: <T extends Array<Selection>>(
variables: { episode?: Episode },
select: (t: CharacterSelector) => T
) =>
this.executor.execute<
IQuery,
Operation<SelectionSet<[Field<"hero", any, SelectionSet<T>>]>>
>(
new Operation(
"hero",
"query",
new SelectionSet([Query.hero<T>(variables, select)])
)
),

reviews: <T extends Array<Selection>>(
variables: { episode?: Episode },
select: (t: ReviewSelector) => T
) =>
this.executor.execute<
IQuery,
Operation<SelectionSet<[Field<"reviews", any, SelectionSet<T>>]>>
>(
new Operation(
"reviews",
"query",
new SelectionSet([Query.reviews<T>(variables, select)])
)
),

search: <T extends Array<Selection>>(
variables: { text?: string },
select: (t: SearchResultSelector) => T
) =>
this.executor.execute<
IQuery,
Operation<SelectionSet<[Field<"search", any, SelectionSet<T>>]>>
>(
new Operation(
"search",
"query",
new SelectionSet([Query.search<T>(variables, select)])
)
),

character: <T extends Array<Selection>>(
variables: { id?: string },
select: (t: CharacterSelector) => T
) =>
this.executor.execute<
IQuery,
Operation<SelectionSet<[Field<"character", any, SelectionSet<T>>]>>
>(
new Operation(
"character",
"query",
new SelectionSet([Query.character<T>(variables, select)])
)
),

droid: <T extends Array<Selection>>(
variables: { id?: string },
select: (t: DroidSelector) => T
) =>
this.executor.execute<
IQuery,
Operation<SelectionSet<[Field<"droid", any, SelectionSet<T>>]>>
>(
new Operation(
"droid",
"query",
new SelectionSet([Query.droid<T>(variables, select)])
)
),

human: <T extends Array<Selection>>(
variables: { id?: string },
select: (t: HumanSelector) => T
) =>
this.executor.execute<
IQuery,
Operation<SelectionSet<[Field<"human", any, SelectionSet<T>>]>>
>(
new Operation(
"human",
"query",
new SelectionSet([Query.human<T>(variables, select)])
)
),

starship: <T extends Array<Selection>>(
variables: { id?: string },
select: (t: StarshipSelector) => T
) =>
this.executor.execute<
IQuery,
Operation<SelectionSet<[Field<"starship", any, SelectionSet<T>>]>>
>(
new Operation(
"starship",
"query",
new SelectionSet([Query.starship<T>(variables, select)])
)
),
};

public readonly mutate = {
createReview: <T extends Array<Selection>>(
variables: { episode?: Episode; review?: ReviewInput },
select: (t: ReviewSelector) => T
) =>
this.executor.execute<
IMutation,
Operation<SelectionSet<[Field<"createReview", any, SelectionSet<T>>]>>
>(
new Operation(
"createReview",
"mutation",
new SelectionSet([Mutation.createReview<T>(variables, select)])
)
),
};
}
34 changes: 28 additions & 6 deletions src/CLI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,46 @@ import {
} from "graphql";

import { Codegen } from "./Codegen";
import { Client } from "./Client";

Yargs.command(
"$0 <schema>",
"Generate a fluent TypeScript client for your GraphQL API.",
(yargs) =>
yargs.positional("schema", {
describe: "ex. https://graphql.org/swapi-graphql/",
type: "string",
demandOption: true,
}),
yargs
.positional("schema", {
describe: "ex. https://graphql.org/swapi-graphql/",
type: "string",
demandOption: true,
})
.option("client", {
type: "string",
requiresArg: true,
description: "Include an implementation of the Client class.",
})
.option("tag", {
type: "string",
default: "unversioned",
description: "Semantic versioning tag (ex. 1.0.0).",
})
.option("module-path", {
type: "string",
description: "Path to @timkendall/tql module.",
}),
async (argv) => {
const schemaPath = argv.schema;

const schema = schemaPath.startsWith("http")
? await remoteSchema(schemaPath)
: await localSchema(schemaPath);

const codegen = new Codegen(schema);
const codegen = new Codegen({
schema,
client: argv.client
? { name: argv.client, version: argv.tag }
: undefined,
modulePath: argv["module-path"],
});

process.stdout.write(codegen.render());
}
Expand Down
22 changes: 22 additions & 0 deletions src/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,28 @@ import { ExecutionResult } from "graphql";

import { SelectionSet, Operation, Result } from "./Operation";

export interface Client {
readonly query: Record<string, unknown>;
readonly mutate?: Record<string, unknown>;
readonly subscribe?: Record<string, unknown>;
}

export class HTTPExecutor implements Executor {
constructor(public readonly endpoint: string) {}

execute<RootType, TOperation extends Operation<SelectionSet<any>>>(
operation: TOperation
): Promise<ExecutionResult<Result<RootType, TOperation["selectionSet"]>>> {
return execute<RootType, TOperation>(this.endpoint, operation);
}
}

export interface Executor {
execute<RootType, TOperation extends Operation<SelectionSet<any>>>(
operation: TOperation
): Promise<ExecutionResult<Result<RootType, TOperation["selectionSet"]>>>;
}

export const execute = <
RootType,
TOperation extends Operation<SelectionSet<any>>
Expand Down
Loading

0 comments on commit 88031b3

Please sign in to comment.