Skip to content

Commit 5271b5a

Browse files
author
Sam Jackson
committed
feat: initial WHERE support
1 parent fbb7873 commit 5271b5a

File tree

11 files changed

+85
-121
lines changed

11 files changed

+85
-121
lines changed

README.md

+23
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,29 @@ const { posts: postsWithAuthorAndComments } = await firegraph.resolve(firestore,
111111
`)
112112
```
113113

114+
### Filtering Results
115+
116+
One of our primary goals is to wrap the Firestore API in its entirety. Filtering
117+
is one of the areas where GraphQL query syntax will really shine:
118+
119+
``` typescript
120+
const authorId = 'sZOgUC33ijsGSzX17ybT';
121+
const { posts: postsBySomeAuthor } = await firegraph.resolve(firestore, gql`
122+
query {
123+
posts(where: {
124+
author: ${authorId},
125+
}) {
126+
id
127+
message
128+
author(matchesKeyFromCollection: "users") {
129+
id
130+
}
131+
}
132+
}
133+
`);
134+
```
135+
136+
114137
# Roadmap
115138

116139
- [x] Querying values from collections

examples/queries/references.graphql

-18
This file was deleted.

examples/queries/types.graphql

-13
This file was deleted.

examples/references.ts

-28
This file was deleted.

examples/types.ts

-23
This file was deleted.

examples/where.ts

-16
This file was deleted.

src/firegraph/Collection.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,26 @@ import { resolveDocument } from './Document';
1313
export async function resolveCollection(
1414
store: firebase.firestore.Firestore,
1515
collectionName: string,
16+
collectionArgs: { [key:string]: any },
1617
selectionSet: GraphQLSelectionSet
1718
): Promise<FiregraphCollectionResult> {
19+
let collectionQuery: any = store.collection(collectionName);
1820
let collectionResult: FiregraphCollectionResult = {
1921
name: collectionName,
2022
docs: []
2123
};
22-
const collectionSnapshot = await store.collection(collectionName).get();
24+
if (collectionArgs) {
25+
if (collectionArgs['where']) {
26+
const where = collectionArgs['where'];
27+
where.forEach((filter: any) => {
28+
collectionQuery = collectionQuery.where(
29+
filter['key'], '==', filter['value']
30+
);
31+
});
32+
}
33+
}
34+
35+
const collectionSnapshot = await collectionQuery.get();
2336
if (selectionSet && selectionSet.selections) {
2437
for (let doc of collectionSnapshot.docs) {
2538
const documentPath = `${collectionName}/${doc.id}`;

src/firegraph/Document.ts

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ export async function resolveDocument(
3333
if (selectionSet && selectionSet.selections) {
3434
let nestedPath: string;
3535
const { matchesKeyFromCollection } = args;
36+
37+
// Document reference.
3638
if (matchesKeyFromCollection) {
3739
const docId = data[fieldName];
3840
nestedPath = `${matchesKeyFromCollection}/${docId}`;
@@ -42,11 +44,14 @@ export async function resolveDocument(
4244
selectionSet
4345
);
4446
docResult[fieldName] = nestedResult;
47+
48+
// Nested collection.
4549
} else {
4650
nestedPath = `${documentPath}/${fieldName}`;
4751
const nestedResult = await resolveCollection(
4852
store,
4953
nestedPath,
54+
args,
5055
selectionSet
5156
);
5257
docResult[fieldName] = nestedResult.docs;

src/firegraph/Where.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export const parseObjectValue = (objectFields: any): any => {
2+
return objectFields.map((field: any) => {
3+
const { name, value } = field;
4+
return {
5+
key: name.value,
6+
value: value.value
7+
};
8+
});
9+
}

src/index.ts

+13-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import firebase from 'firebase/app';
22
import 'firebase/firestore';
33

44
// Top-level imports related to Firegraph.
5+
import { parseObjectValue } from './firegraph/Where';
56
import { resolveCollection } from './firegraph/Collection';
67
import { FiregraphResult } from './types/Firegraph';
78

@@ -30,15 +31,26 @@ async function resolve(
3031
for (let collection of targetCollections) {
3132
const {
3233
name: { value: collectionName },
33-
selectionSet
34+
selectionSet,
35+
arguments: collectionArguments,
3436
} = collection;
3537

38+
// Parse the GraphQL argument AST into something we can use.
39+
const parsedArgs: any = {};
40+
collectionArguments.forEach((arg: any) => {
41+
if (arg.value.kind === 'ObjectValue') {
42+
const { fields } = arg.value;
43+
parsedArgs[arg.name.value] = parseObjectValue(fields);
44+
}
45+
});
46+
3647
// Now we begin to recursively fetch values defined in GraphQL
3748
// selection sets. We pass our `firestore` instance to ensure
3849
// all selections are done from the same database.
3950
const result = await resolveCollection(
4051
firestore,
4152
collectionName,
53+
parsedArgs,
4254
selectionSet
4355
);
4456

test/firegraph.test.ts

+21-21
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ describe('firegraph', () => {
1313
}
1414
`);
1515

16-
expect(posts).toHaveLength(1);
1716
posts.map((post: any) => {
1817
expect(post).toHaveProperty('id');
1918
expect(post).toHaveProperty('message');
@@ -70,24 +69,25 @@ describe('firegraph', () => {
7069
});
7170
});
7271

73-
// it('can filter results with WHERE clause', async () => {
74-
// const { posts } = await firegraph.resolve(firestore, gql`
75-
// query {
76-
// posts(where: {
77-
// author: "sZOgUC33ijsGSzX17ybT"
78-
// }) {
79-
// id
80-
// message
81-
// author(matchesKeyFromCollection: "users") {
82-
// id
83-
// }
84-
// }
85-
// }
86-
// `);
87-
// posts.forEach((post: any) => {
88-
// expect(post).toHaveProperty('author');
89-
// expect(post.author).toHaveProperty('id');
90-
// expect(post.author.id).toEqual('sZOgUC33ijsGSzX17ybT');
91-
// });
92-
// });
72+
it('can filter results with WHERE clause', async () => {
73+
const authorId = 'sZOgUC33ijsGSzX17ybT';
74+
const { posts } = await firegraph.resolve(firestore, gql`
75+
query {
76+
posts(where: {
77+
author: ${authorId},
78+
}) {
79+
id
80+
message
81+
author(matchesKeyFromCollection: "users") {
82+
id
83+
}
84+
}
85+
}
86+
`);
87+
posts.forEach((post: any) => {
88+
expect(post).toHaveProperty('author');
89+
expect(post.author).toHaveProperty('id');
90+
expect(post.author.id).toEqual('sZOgUC33ijsGSzX17ybT');
91+
});
92+
});
9393
});

0 commit comments

Comments
 (0)