Skip to content

Commit

Permalink
fix: WHERE filters were not behaving as expected
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Jackson committed Feb 4, 2019
1 parent 12b3313 commit d2a0b1b
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 68 deletions.
34 changes: 33 additions & 1 deletion lib/firegraph/Collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,39 @@ function resolveCollection(store, collectionName, collectionArgs, selectionSet)
if (collectionArgs['where']) {
const where = collectionArgs['where'];
where.forEach((filter) => {
collectionQuery = collectionQuery.where(filter['key'], '==', filter['value']);
const key = filter['key'];
const value = filter['value'];
const splitKey = key.split('_');
const whereOp = splitKey[splitKey.length - 1];
switch (whereOp) {
case 'neq':
collectionQuery = collectionQuery
.where(key, '>', value)
.where(key, '<', value);
break;
case 'gt':
collectionQuery = collectionQuery
.where(key, '>', value);
break;
case 'gte':
collectionQuery = collectionQuery
.where(key, '>', value)
.where(key, '==', value);
break;
case 'lt':
collectionQuery = collectionQuery
.where(key, '<', value);
break;
case 'lte':
collectionQuery = collectionQuery
.where(key, '<', value)
.where(key, '==', value);
break;
default:
collectionQuery = collectionQuery
.where(key, '==', value);
break;
}
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "firegraph",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"version": "1.0.8",
"version": "1.0.9",
"license": "MIT",
"scripts": {
"test": "jest --env=jsdom --browser",
Expand Down
40 changes: 4 additions & 36 deletions src/firegraph/Collection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { GraphQLSelectionSet } from '../types/GraphQL';
import { FiregraphCollectionResult } from '../types/Firegraph';
import { resolveDocument } from './Document';
import { setQueryFilters } from './Where';

/**
* Retrieves documents from a specified collection path. Currently retrieves
Expand All @@ -21,47 +22,14 @@ export async function resolveCollection(
name: collectionName,
docs: []
};

if (collectionArgs) {
if (collectionArgs['where']) {
const where = collectionArgs['where'];
where.forEach((filter: any) => {
const key: string = filter['key'];
const value: string = filter['value'];
const splitKey: string[] = key.split('_');
const whereOp = splitKey[splitKey.length - 1];
switch (whereOp) {
case 'neq':
collectionQuery = collectionQuery
.where(key, '>', value)
.where(key, '<', value);
break;
case 'gt':
collectionQuery = collectionQuery
.where(key, '>', value);
break;
case 'gte':
collectionQuery = collectionQuery
.where(key, '>', value)
.where(key, '==', value);
break;
case 'lt':
collectionQuery = collectionQuery
.where(key, '<', value);
break;
case 'lte':
collectionQuery = collectionQuery
.where(key, '<', value)
.where(key, '==', value);
break;
default:
collectionQuery = collectionQuery
.where(key, '==', value);
break;
}
});
collectionQuery = setQueryFilters(collectionQuery, where);
}
}

const collectionSnapshot = await collectionQuery.get();
if (selectionSet && selectionSet.selections) {
for (let doc of collectionSnapshot.docs) {
Expand Down
46 changes: 46 additions & 0 deletions src/firegraph/Where.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,55 @@
/**
* Parses GraphQL AST to get complex parameters to GraphQL queries.
* @param objectFields Set of key-value pairs in GraphQL AST form.
*/
export const parseObjectValue = (objectFields: any): any => {
return objectFields.map((field: any) => {
const { name, value } = field;
if (value.kind === 'IntValue') value.value = parseInt(value.value);

return {
key: name.value,
value: value.value
};
});
}

/**
* Applies filters to a Firestore query. Basically chains a series of
* calls to `firestore.collection#where`.
* @param collectionQuery The query to be made against some collection.
* @param where Set of filters formatted as `KEY_COMPARATOR: VALUE` pairs
*/
export const setQueryFilters = (
collectionQuery: any,
where: any[]
): firebase.firestore.Query => {
where.forEach((filter: any) => {
const key: string = filter['key'];
const value: any = filter['value'];
const splitKey: string[] = key.split('_');
const whereOp = splitKey[splitKey.length - 1];
const actualKey = key.slice(0, -1 * (whereOp.length + 1));
switch (whereOp) {
case 'eq':
collectionQuery = collectionQuery.where(actualKey, '==', value);
break;
case 'gt':
collectionQuery = collectionQuery.where(actualKey, '>', value);
break;
case 'gte':
collectionQuery = collectionQuery.where(actualKey, '>=', value);
break;
case 'lt':
collectionQuery = collectionQuery.where(actualKey, '<', value);
break;
case 'lte':
collectionQuery = collectionQuery.where(actualKey, '<=', value);
break;
default:
collectionQuery = collectionQuery.where(key, '==', value);
break;
}
});
return collectionQuery;
}
102 changes: 72 additions & 30 deletions test/firegraph.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,45 +69,87 @@ describe('firegraph', () => {
});
});

it('can filter results with WHERE clause', async () => {
const authorId = 'sZOgUC33ijsGSzX17ybT';
const { posts } = await firegraph.resolve(firestore, gql`
query {
posts(where: {
author: ${authorId},
}) {
id
message
author(matchesKeyFromCollection: "users") {
describe('WHERE', () => {
it('can filter with key-value equality', async () => {
const authorId = 'sZOgUC33ijsGSzX17ybT';
const { posts } = await firegraph.resolve(firestore, gql`
query {
posts(where: {
author: ${authorId},
}) {
id
message
author(matchesKeyFromCollection: "users") {
id
}
}
}
}
`);
`);

posts.forEach((post: any) => {
expect(post).toHaveProperty('author');
expect(post.author).toHaveProperty('id');
expect(post.author.id).toEqual('sZOgUC33ijsGSzX17ybT');
});
});
it('can filter with `_gt` operator', async () => {
const { posts } = await firegraph.resolve(firestore, gql`
query {
posts(where: {
score_gt: 6,
}) {
id
score
}
}
`);

posts.forEach((post: any) => {
expect(post).toHaveProperty('author');
expect(post.author).toHaveProperty('id');
expect(post.author.id).toEqual('sZOgUC33ijsGSzX17ybT');
expect(posts).toHaveLength(1);
});
});

it('can filter results with WHERE operations', async () => {
const authorId = 'sZOgUC33ijsGSzX17ybT';
const { posts } = await firegraph.resolve(firestore, gql`
query {
posts(where: {
author_neq: ${authorId},
}) {
id
message
author(matchesKeyFromCollection: "users") {
it('can filter with `_gte` operator', async () => {
const { posts } = await firegraph.resolve(firestore, gql`
query {
posts(where: {
score_gte: 6,
}) {
id
score
}
}
}
`);
`);

expect(posts).toHaveLength(2);
});

it('can filter with `_lt` operator', async () => {
const { posts } = await firegraph.resolve(firestore, gql`
query {
posts(where: {
score_lt: 14,
}) {
id
score
}
}
`);

expect(posts).toHaveLength(1);
});

expect(posts).toHaveLength(0);
it('can filter with `_lte` operator', async () => {
const { posts } = await firegraph.resolve(firestore, gql`
query {
posts(where: {
score_lte: 14,
}) {
id
score
}
}
`);

expect(posts).toHaveLength(2);
});
});
});

0 comments on commit d2a0b1b

Please sign in to comment.