Skip to content

Commit

Permalink
feat(graphql): selecing sub sets and interfaces along with fields #596
Browse files Browse the repository at this point in the history
  • Loading branch information
satanTime committed Jun 4, 2021
1 parent 85a1f40 commit 3d3857a
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 9 deletions.
17 changes: 16 additions & 1 deletion docs/articles/guide/graphql/quick.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ And we want to build a **GraphQL** query that fetches a user, its company and th
id
firstName
lastName
permissions {
level
}
companyId
company {
id
Expand Down Expand Up @@ -57,7 +60,17 @@ and add meta information about **GraphQL**.
// user
export const rootUser = rootEntitySelector(selectUserState, {
// here we go
gqlFields: ['id', 'firstName', 'lastName'],
// usually we could define an array
// but because `permissions` isn't
// a normal field, we need to define
// an object, where values of its keys
// are an empty string or a sub query
gqlFields: {
id: '',
firstName: '',
lastName: '',
permissions: '{level}',
},
});
// user.company
export const relUserCompany = relatedEntitySelector(
Expand All @@ -66,6 +79,8 @@ export const relUserCompany = relatedEntitySelector(
'company',
{
// here we go
// no sub queries, therefore
// we can use an array
gqlFields: ['id', 'name'],
},
);
Expand Down
71 changes: 71 additions & 0 deletions libs/ngrx-entity-relationship/e2e/issues/596.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {FEATURE_SELECTOR, relatedEntitySelector, rootEntitySelector} from 'ngrx-entity-relationship';
import {toGraphQL} from 'ngrx-entity-relationship/graphql';

// A way to provide subset selectors
describe('issue-596', () => {
const normalizeQuery = (query: string) => {
return query.replace(/\s+/gim, ' ').replace(/\s*([\[\]{}():,])\s*/gim, '$1');
};
interface User {
id: string;
firstName: string;
lastName: string;
permissions: Array<{
key: string;
level: string;
}>;
company?: Company;
companyId?: string;
}
interface Company {
id: string;
name: string;
staff?: Array<User>;
admin?: User;
adminId?: string;
}

const userFeature: FEATURE_SELECTOR<any, User> = (() => undefined) as any;
const companyFeature: FEATURE_SELECTOR<any, Company> = (() => undefined) as any;

const user = rootEntitySelector(userFeature, {
gqlFields: {
id: '',
firstName: '',
lastName: '',
permissions: '{key level}',
company: '{id}', // will be ignored due to the selector
},
});
const userCompany = relatedEntitySelector(companyFeature, 'companyId', 'company', {
gqlFields: ['id', 'name'],
});

const selectUser = user(userCompany());

afterEach(() => ((window as any).ngrxGraphqlPrefix = undefined));

it('adds sub sets to the final query', () => {
const query = toGraphQL('users', selectUser);
expect(normalizeQuery(query)).toEqual(
normalizeQuery(`
{
users {
companyId
company {
id
name
}
id
firstName
lastName
permissions {
key
level
}
}
}
`),
);
});
});
33 changes: 26 additions & 7 deletions libs/ngrx-entity-relationship/graphql/src/lib/toGraphQL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,27 @@ const resolveGraphQL = (
included.push(field);
query += `${prefix}${field}\n`;
}
const fields = selector.meta.gqlFields || [];
for (const field of fields) {
if (included.indexOf(field) !== -1) {
continue;
if (Array.isArray(selector.meta.gqlFields)) {
for (const field of selector.meta.gqlFields) {
if (included.indexOf(field) !== -1) {
continue;
}
included.push(field);
query += `${prefix}${field}\n`;
}
} else if (selector.meta.gqlFields) {
for (const field of Object.keys(selector.meta.gqlFields)) {
if (included.indexOf(field) !== -1) {
continue;
}
included.push(field);
query += `${prefix}${field}${selector.meta.gqlFields[field]}\n`;
}
included.push(field);
query += `${prefix}${field}\n`;
}
return query;
};

function encodeValue(data: any): string | undefined {
function encodeValuePrimitives(data: any): string | undefined {
if (typeof data === 'number') {
return JSON.stringify(data);
}
Expand All @@ -81,6 +90,16 @@ function encodeValue(data: any): string | undefined {
if (typeof data === 'boolean') {
return JSON.stringify(data);
}

return undefined;
}

function encodeValue(data: any): string | undefined {
const primitives = encodeValuePrimitives(data);
if (primitives !== undefined) {
return primitives;
}

if (data === null || data === undefined) {
return JSON.stringify(null);
}
Expand Down
2 changes: 1 addition & 1 deletion libs/ngrx-entity-relationship/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ declare global {
// tslint:disable-next-line:class-name
export interface SELECTOR_META {
flatKey?: string;
gqlFields?: Array<string | number>;
gqlFields?: Array<string | number> | Record<string, string>;
}
}

Expand Down

0 comments on commit 3d3857a

Please sign in to comment.