Skip to content

Commit

Permalink
Support (non-typed) DocumentNode and add tests for typing
Browse files Browse the repository at this point in the history
  • Loading branch information
izumin5210 committed Sep 13, 2021
1 parent fe89d41 commit f2c4238
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 24 deletions.
57 changes: 44 additions & 13 deletions src/maskWithFragment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ import * as multipleFragmentsFixtures from "./__fixtures__/graphql/__generated__
import * as rootListFixtures from "./__fixtures__/graphql/__generated__/rootList.generated";
import * as unionFixtures from "./__fixtures__/graphql/__generated__/union.generated";

const expectType = <T>(_value: T) => {
/* no-op */
};

it("masks query results with simple fragment", () => {
const input: simpleFixtures.GetUserHeaderQuery = {
__typename: "Query",
Expand All @@ -26,7 +22,6 @@ Object {
"username": "testuser",
}
`);
expectType<simpleFixtures.UserHeaderFragment>(output);
});

it("masks query results with nested fragment", () => {
Expand All @@ -52,7 +47,6 @@ Object {
"title": "Hi",
}
`);
expectType<nestedFixtures.PostHeaderFragment>(output);
});

it("masks query results with nested fragment with list fields", () => {
Expand Down Expand Up @@ -88,7 +82,6 @@ Object {
"title": "Hi",
}
`);
expectType<nestedListFixtures.PostWithCommentsFragment>(output);
});

it("masks query results with inline fragment", () => {
Expand All @@ -113,7 +106,6 @@ Object {
"title": "Hi",
}
`);
expectType<inlineFragmentFixtures.PostWithAuthorFragment>(output);
});

it("masks query results with fragment with alias", () => {
Expand Down Expand Up @@ -141,7 +133,6 @@ Object {
},
}
`);
expectType<aliasFixtures.PostSummaryFragment>(output);
});

it("masks query results with multiple fragments", () => {
Expand Down Expand Up @@ -169,7 +160,6 @@ Object {
"title": "Hi",
}
`);
expectType<multipleFragmentsFixtures.PostDetailFragment>(detail);

const detailHeader = maskWithFragment(multipleFragmentsFixtures.PostDetailHeaderFragmentDoc, input.postById);
expect(detailHeader).toMatchInlineSnapshot(`
Expand All @@ -182,7 +172,6 @@ Object {
"title": "Hi",
}
`);
expectType<multipleFragmentsFixtures.PostDetailHeaderFragment>(detailHeader);
});

it("masks list query results with fragment", () => {
Expand Down Expand Up @@ -229,7 +218,6 @@ Array [
},
]
`);
expectType<ReadonlyArray<rootListFixtures.PostListItemFragment>>(output);
});

it("masks list query results with fragment", () => {
Expand Down Expand Up @@ -267,5 +255,48 @@ Object {
"title": "Hi",
}
`);
expectType<unionFixtures.PostWithAttachmentsFragment>(output);
});

const expectType = <T>(_value: T) => {
/* no-op */
};

describe("types", () => {
const input: simpleFixtures.GetUserHeaderQuery = {
__typename: "Query",
userById: { __typename: "User", id: "123", username: "testuser", avatarUrl: null },
};

describe("with typed document node", () => {
it("returns a masked result with a valid type", () => {
const output = maskWithFragment(simpleFixtures.UserHeaderFragmentDoc, input.userById);
expectType<simpleFixtures.UserHeaderFragment>(output);
});

it("has type error when 2nd argument is not a subset type of the return value", () => {
expect(() => {
// @ts-expect-error: 2nd argument has invalid type
maskWithFragment(simpleFixtures.UserHeaderFragmentDoc, {});
}).toThrowError();
});
});

describe("with document node", () => {
it("returns a masked result with a record when type parameter is not specified", () => {
const output = maskWithFragment(simpleFixtures.UserHeader, input.userById);
expectType<Record<string, unknown>>(output);
});

it("returns a masked result with a valid type when type parameter is specified", () => {
const output = maskWithFragment<simpleFixtures.UserHeaderFragment>(simpleFixtures.UserHeader, input.userById);
expectType<simpleFixtures.UserHeaderFragment>(output);
});

it("has type error when 2nd argument is not a subset type of the return value", () => {
expect(() => {
// @ts-expect-error: 2nd argument has invalid type
maskWithFragment<simpleFixtures.UserHeaderFragment>(simpleFixtures.UserHeader, {});
}).toThrowError();
});
});
});
25 changes: 14 additions & 11 deletions src/maskWithFragment.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import { TypedDocumentNode } from "@graphql-typed-document-node/core";
import { FragmentDefinitionNode, InlineFragmentNode } from "graphql";
import { FragmentDefinitionNode, DocumentNode, InlineFragmentNode } from "graphql";
import deepMerge from "deepmerge";

export function maskWithFragment<TFilteredData extends Record<string, unknown>, TData extends TFilteredData>(
doc: TypedDocumentNode<TFilteredData, any>,
input: TData
): TFilteredData;
export function maskWithFragment<TFilteredData extends Record<string, unknown>, TData extends TFilteredData>(
doc: TypedDocumentNode<TFilteredData, any>,
input: ReadonlyArray<TData>
): ReadonlyArray<TFilteredData>;
export function maskWithFragment<TFilteredData extends Record<string, unknown>, TData extends TFilteredData>(
doc: TypedDocumentNode<TFilteredData, any>,
export function maskWithFragment<
TFilteredData extends Record<string, unknown>,
TData extends TFilteredData = TFilteredData
>(doc: DocumentNode | TypedDocumentNode<TFilteredData, any>, input: TData): TFilteredData;
export function maskWithFragment<
TFilteredData extends Record<string, unknown>,
TData extends TFilteredData = TFilteredData
>(doc: DocumentNode | TypedDocumentNode<TFilteredData, any>, input: ReadonlyArray<TData>): ReadonlyArray<TFilteredData>;
export function maskWithFragment<
TFilteredData extends Record<string, unknown>,
TData extends TFilteredData = TFilteredData
>(
doc: DocumentNode | TypedDocumentNode<TFilteredData, any>,
input: TData | ReadonlyArray<TData>
): TFilteredData | ReadonlyArray<TFilteredData> {
if (doc.definitions[0]?.kind !== "FragmentDefinition") {
Expand Down

0 comments on commit f2c4238

Please sign in to comment.