Skip to content

Commit 24fe251

Browse files
committed
Add support for gql tag
1 parent 9e42cbb commit 24fe251

File tree

7 files changed

+131
-15
lines changed

7 files changed

+131
-15
lines changed

docs/guide/custom-queries/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ Following fields are allowed:
117117
- `variables`: Variables to pass
118118
- `bypassCache`: Whether to bypass the caching.
119119

120+
::: tip
121+
As `query` you can also pass a GraphQL AST DocumentNode like it's returned by the `gql` function or
122+
the `*.graphql` webpack loader of [graphql-tag](https://github.com/apollographql/graphql-tag).
123+
:::
120124

121125
## Model related custom mutation
122126

@@ -216,6 +220,11 @@ Following fields are allowed:
216220
- `query`: Required. The GraphQL mutation query.
217221
- `variables`: Hash map with variables to pass.
218222

223+
::: tip
224+
As `query` you can also pass a GraphQL AST DocumentNode like it's returned by the `gql` function or
225+
the `*.graphql` webpack loader of [graphql-tag](https://github.com/apollographql/graphql-tag).
226+
:::
227+
219228

220229
## Multiple or single record
221230

src/actions/simple-mutation.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { ActionParams } from "../support/interfaces";
22
import Action from "./action";
33
import Context from "../common/context";
4-
import { parse } from "graphql/language/parser";
5-
import { clone } from "../support/utils";
4+
import { clone, graphQlDocumentToString, parseQuery } from "../support/utils";
65

76
/**
87
* SimpleMutation action for sending a model unrelated simple mutation.
@@ -21,7 +20,8 @@ export default class SimpleMutation extends Action {
2120
const context: Context = Context.getInstance();
2221

2322
if (query) {
24-
const parsedQuery = parse(query);
23+
const parsedQuery = parseQuery(query);
24+
2525
const mockReturnValue = context.globalMockHook("simpleMutation", {
2626
name: parsedQuery.definitions[0]["name"].value,
2727
variables
@@ -32,7 +32,10 @@ export default class SimpleMutation extends Action {
3232
}
3333

3434
variables = this.prepareArgs(variables);
35-
const result = await context.apollo.simpleMutation(query, variables);
35+
const result = await context.apollo.simpleMutation(
36+
graphQlDocumentToString(parsedQuery),
37+
variables
38+
);
3639

3740
// remove the symbols
3841
return clone(result.data);

src/actions/simple-query.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { ActionParams } from "../support/interfaces";
22
import Action from "./action";
33
import Context from "../common/context";
4-
import { parse } from "graphql/language/parser";
5-
import { clone, removeSymbols } from "../support/utils";
4+
import { clone, graphQlDocumentToString, parseQuery, removeSymbols } from "../support/utils";
65

76
/**
87
* SimpleQuery action for sending a model unrelated simple query.
@@ -22,7 +21,8 @@ export default class SimpleQuery extends Action {
2221
const context: Context = Context.getInstance();
2322

2423
if (query) {
25-
const parsedQuery = parse(query);
24+
const parsedQuery = parseQuery(query);
25+
2626
const mockReturnValue = context.globalMockHook("simpleQuery", {
2727
name: parsedQuery.definitions[0]["name"].value,
2828
variables
@@ -34,7 +34,11 @@ export default class SimpleQuery extends Action {
3434

3535
variables = this.prepareArgs(variables);
3636

37-
const result = await context.apollo.simpleQuery(query, variables, bypassCache);
37+
const result = await context.apollo.simpleQuery(
38+
graphQlDocumentToString(parsedQuery),
39+
variables,
40+
bypassCache
41+
);
3842

3943
// remove the symbols
4044
return removeSymbols(clone(result.data));

src/graphql/schema.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ export default class Schema {
5656
name = upcaseFirstLetter(name);
5757
const type = this.types.get(name);
5858

59-
if (!allowNull && !type)
59+
if (!allowNull && !type) {
6060
throw new Error(`Couldn't find Type of name ${name} in the GraphQL Schema.`);
61+
}
6162

6263
return type || null;
6364
}
@@ -66,8 +67,9 @@ export default class Schema {
6667
const mutation = this.mutations.get(name);
6768

6869
/* istanbul ignore next */
69-
if (!allowNull && !mutation)
70+
if (!allowNull && !mutation) {
7071
throw new Error(`Couldn't find Mutation of name ${name} in the GraphQL Schema.`);
72+
}
7173

7274
return mutation || null;
7375
}
@@ -76,8 +78,9 @@ export default class Schema {
7678
const query = this.queries.get(name);
7779

7880
/* istanbul ignore next */
79-
if (!allowNull && !query)
81+
if (!allowNull && !query) {
8082
throw new Error(`Couldn't find Query of name ${name} in the GraphQL Schema.`);
83+
}
8184

8285
return query || null;
8386
}

src/support/interfaces.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { Database, Model as ORMModel } from "@vuex-orm/core";
33
import RootState from "@vuex-orm/core/lib/modules/contracts/RootState";
44
import { ApolloLink } from "apollo-link";
5+
import { DocumentNode } from "graphql/language/ast";
56

67
export type DispatchFunction = (action: string, data: Data) => Promise<any>;
78

@@ -29,7 +30,7 @@ export interface ActionParams {
2930
args?: Arguments;
3031
variables?: Arguments;
3132
bypassCache?: boolean;
32-
query?: string;
33+
query?: string | DocumentNode;
3334
multiple?: boolean;
3435
name?: string;
3536
}

src/support/utils.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { parse } from "graphql/language/parser";
22
import { print } from "graphql/language/printer";
3+
import { DocumentNode } from "graphql/language/ast";
34

45
// @ts-ignore
56
import lodashIsEqual from "lodash.isequal";
@@ -37,14 +38,34 @@ export function downcaseFirstLetter(input: string) {
3738
* @param {string} query
3839
* @returns {string}
3940
*/
40-
export function prettify(query: string): string {
41-
return print(parse(query));
41+
export function prettify(query: string | DocumentNode): string {
42+
return print(parseQuery(query));
43+
}
44+
45+
/**
46+
* Returns a parsed query as GraphQL AST DocumentNode.
47+
*
48+
* @param {string | DocumentNode} query - Query as string or GraphQL AST DocumentNode.
49+
*
50+
* @returns {DocumentNode} Query as GraphQL AST DocumentNode.
51+
*/
52+
export function parseQuery(query: string | DocumentNode): DocumentNode {
53+
return typeof query === "string" ? parse(query) : query;
54+
}
55+
56+
/**
57+
* @param {DocumentNode} query - The GraphQL AST DocumentNode.
58+
*
59+
* @returns {string} the GraphQL query within a DocumentNode as a plain string.
60+
*/
61+
export function graphQlDocumentToString(query: DocumentNode): string {
62+
return query.loc!.source.body;
4263
}
4364

4465
/**
4566
* Tells if a object is just a simple object.
4667
*
47-
* @param {any} value - Value to check.
68+
* @param {any} obj - Value to check.
4869
*/
4970
export function isPlainObject(obj: any): boolean {
5071
// Basic check for Type object that's not null

test/integration/plugin.spec.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { setupMockData, User, Profile, Post, Tariff, Category, Tag } from "../support/mock-data";
22
import Context from "../../src/common/context";
33
import { recordGraphQLRequest } from "../support/helpers";
4+
import gql from "graphql-tag";
45

56
let store: any;
67
let vuexOrmGraphQL;
@@ -815,6 +816,42 @@ mutation SendSms($to: String!, $text: String!) {
815816
sendSms(to: $to, text: $text) {
816817
delivered
817818
}
819+
}
820+
`.trim() + "\n"
821+
);
822+
});
823+
824+
test("also accepts GraphQL AST DocumentNode", async () => {
825+
let result;
826+
827+
const query = gql`
828+
mutation SendSms($to: String!, $text: String!) {
829+
sendSms(to: $to, text: $text) {
830+
delivered
831+
}
832+
}
833+
`;
834+
835+
const request = await recordGraphQLRequest(async () => {
836+
result = await store.dispatch("entities/simpleMutation", {
837+
query,
838+
variables: { to: "+4912345678", text: "GraphQL is awesome!" }
839+
});
840+
});
841+
842+
expect(request!.variables).toEqual({ to: "+4912345678", text: "GraphQL is awesome!" });
843+
expect(result).toEqual({
844+
sendSms: {
845+
__typename: "SmsStatus", // TODO: this could removed by Vuex-ORM-GraphQL IMHO
846+
delivered: true
847+
}
848+
});
849+
expect(request!.query).toEqual(
850+
`
851+
mutation SendSms($to: String!, $text: String!) {
852+
sendSms(to: $to, text: $text) {
853+
delivered
854+
}
818855
}
819856
`.trim() + "\n"
820857
);
@@ -855,6 +892,44 @@ query Status {
855892
smsGateway
856893
paypalIntegration
857894
}
895+
}
896+
`.trim() + "\n"
897+
);
898+
});
899+
test("also accepts GraphQL AST DocumentNode", async () => {
900+
let result;
901+
902+
const query = gql`
903+
query Status {
904+
status {
905+
backend
906+
smsGateway
907+
paypalIntegration
908+
}
909+
}
910+
`;
911+
912+
const request = await recordGraphQLRequest(async () => {
913+
result = await store.dispatch("entities/simpleQuery", { query, variables: {} });
914+
});
915+
916+
expect(result).toEqual({
917+
status: {
918+
__typename: "Status",
919+
backend: true,
920+
paypalIntegration: true,
921+
smsGateway: false
922+
}
923+
});
924+
925+
expect(request!.query).toEqual(
926+
`
927+
query Status {
928+
status {
929+
backend
930+
smsGateway
931+
paypalIntegration
932+
}
858933
}
859934
`.trim() + "\n"
860935
);

0 commit comments

Comments
 (0)