Skip to content

Commit

Permalink
Add directive support to the tiny operation compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
airhorns committed Jul 24, 2023
1 parent 1987003 commit 278a0bc
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 14 deletions.
2 changes: 1 addition & 1 deletion packages/tiny-graphql-query-compiler/spec/calls.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ describe("compiling queries with field calls", () => {
"query {
id
name
truncatedHTML
truncatedHTML(length: $length)
}"
`);
expect(variables).toEqual({});
Expand Down
49 changes: 48 additions & 1 deletion packages/tiny-graphql-query-compiler/spec/query.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { compile } from "../src";
import { Call, Var, compile } from "../src";
import { expectValidGraphQLQuery } from "./helpers";

describe("compiling queries", () => {
Expand Down Expand Up @@ -156,4 +156,51 @@ describe("compiling queries", () => {
}"
`);
});

test("it should compile a query with a live directives", () => {
const result = compile({
type: "query",
name: "GetUsers",
fields: {
id: true,
name: true,
age: true,
},
directives: ["@live"],
});

expectValidGraphQLQuery(result);
expect(result).toMatchInlineSnapshot(`
"query GetUsers @live {
id
name
age
}"
`);
});

test("it should compile a query with variables and a live directives", () => {
const result = compile({
type: "query",
name: "GetUsers",
fields: {
user: Call(
{ id: Var({ type: "ID" }) },
{
id: true,
}
),
},
directives: ["@live"],
});

expectValidGraphQLQuery(result);
expect(result).toMatchInlineSnapshot(`
"query GetUsers($id: ID) @live {
user(id: $id) {
id
}
}"
`);
});
});
24 changes: 12 additions & 12 deletions packages/tiny-graphql-query-compiler/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface BuilderOperation {
type: "query" | "subscription" | "mutation";
fields: FieldSelection;
name?: string;
directives?: string[];
}

const indent = (str: string, depth: number) => {
Expand Down Expand Up @@ -80,15 +81,12 @@ const compileVariables = (operation: BuilderOperation, onlyPresentValues = false
}
}

if (Object.keys(variables).length === 0) return { variables, signature: "" };
if (Object.keys(variables).length === 0) return "";
const signatures = Object.entries(variables).map(([name, variable]) => {
return `$${name}: ${variable.type}${variable.required ? "!" : ""}`;
});

return {
variables,
signature: `(${signatures.join(", ")})`,
};
return `(${signatures.join(", ")})`;
};

class FieldCall {
Expand All @@ -102,6 +100,7 @@ export interface VariableOptions {
value?: any;
}

/** Represents one reference to a variable somewhere in a selection */
export class Variable {
constructor(readonly type: string, readonly required = false, readonly name?: string, readonly value?: any) {}
}
Expand All @@ -113,20 +112,21 @@ export const Call = (args: Record<string, Variable | any>, subselection?: FieldS
export const Var = (options: VariableOptions) => new Variable(options.type, options.required, options.name, options.value);

/** Compiles one JS object describing a query into a GraphQL string */
export const compile = (operation: BuilderOperation): string => {
const { signature } = compileVariables(operation);
return `${operation.type} ${operation.name ?? ""}${signature} {
export const compile = (operation: BuilderOperation, onlyPresentVariableValues = false): string => {
const signature = compileVariables(operation, onlyPresentVariableValues);
const directives = operation.directives && operation.directives.length > 0 ? ` ${operation.directives.join(" ")}` : "";

return `${operation.type} ${operation.name ?? ""}${signature}${directives} {
${compileFieldSelection(operation.fields)}
}`;
};

/** Compiles one JS object describing a query into a GraphQL string and set of variable values for passing alongside the query */
export const compileWithVariableValues = (operation: BuilderOperation): { query: string; variables: Record<string, any> } => {
const { signature, variables } = compileVariables(operation, true);
const variables = extractVariables(operation.fields);

return {
query: `${operation.type} ${operation.name ?? ""}${signature} {
${compileFieldSelection(operation.fields, true)}
}`,
query: compile(operation, true),
variables: Object.entries(variables ?? {}).reduce((acc, [name, variable]) => {
acc[name] = variable.value;
return acc;
Expand Down

0 comments on commit 278a0bc

Please sign in to comment.