Skip to content

Commit

Permalink
feat: NOT, AND, OR (#215)
Browse files Browse the repository at this point in the history
Co-authored-by: Nicola Marcacci Rossi <[email protected]>
  • Loading branch information
nickredmark and nicola-smartive authored Oct 16, 2024
1 parent d53dac2 commit 4d51338
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 2 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ See the [docs](https://)

## Development

```
npm run deps
```

```
npm bootstrap
```
Expand Down
30 changes: 30 additions & 0 deletions src/resolvers/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,36 @@ const applyWhere = (node: WhereNode, where: Where, ops: QueryBuilderOps, joins:
for (const key of Object.keys(where)) {
const value = where[key];

if (key === 'NOT') {
const subOps: QueryBuilderOps = [];
applyWhere(node, value as Where, subOps, joins);
ops.push((query) => query.whereNot((subQuery) => apply(subQuery, subOps)));
continue;
}

if (key === 'AND') {
for (const subWhere of value as Where[]) {
applyWhere(node, subWhere, ops, joins);
}
continue;
}

if (key === 'OR') {
const allSubOps: QueryBuilderOps[] = [];
for (const subWhere of value as Where[]) {
const subOps: QueryBuilderOps = [];
applyWhere(node, subWhere, subOps, joins);
allSubOps.push(subOps);
}
ops.push((query) =>
ors(
query,
allSubOps.map((subOps) => (subQuery) => apply(subQuery, subOps))
)
);
continue;
}

const specialFilter = key.match(/^(\w+)_(\w+)$/);
if (specialFilter) {
const [, actualKey, filter] = specialFilter;
Expand Down
14 changes: 14 additions & 0 deletions src/schema/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,20 @@ export const generateDefinitions = ({
type: `${relation.targetModel.name}Where`,
},
]),
{
name: 'NOT',
type: `${model.name}Where`,
},
{
name: 'AND',
type: `${model.name}Where`,
list: true,
},
{
name: 'OR',
type: `${model.name}Where`,
list: true,
},
]),
input(
`${model.name}WhereUnique`,
Expand Down
36 changes: 36 additions & 0 deletions tests/api/__snapshots__/query.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`query AND works 1`] = `
{
"manyObjects": [
{
"id": "fc4e013e-4cb0-4ef8-9f2e-3d475bdf2b90",
},
],
}
`;

exports[`query NOT works 1`] = `
{
"manyObjects": [
{
"id": "fc4e013e-4cb0-4ef8-9f2e-3d475bdf2b90",
},
{
"id": "37a23870-e7f5-45c8-86e5-f14d9f2405f9",
},
],
}
`;

exports[`query OR works 1`] = `
{
"manyObjects": [
{
"id": "fc4e013e-4cb0-4ef8-9f2e-3d475bdf2b90",
},
{
"id": "604ab55d-ec3e-4857-9f27-219158f80e64",
},
],
}
`;

exports[`query can be executed 1`] = `
{
"manyObjects": [
Expand Down
44 changes: 43 additions & 1 deletion tests/api/query.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { gql } from '../../src';
import { ANOTHER_ID, SOME_ID } from '../utils/database/seed';
import { ANOTHER_ID, SOME_ID, SOME_ID_2 } from '../utils/database/seed';
import { withServer } from '../utils/server';

describe('query', () => {
Expand Down Expand Up @@ -72,4 +72,46 @@ describe('query', () => {
).toMatchSnapshot();
});
});

it('NOT works', async () => {
await withServer(async (request) => {
expect(
await request(gql`
query NotQuery {
manyObjects(where: { NOT: { id: "${SOME_ID}" } }, orderBy: [{ xyz: DESC }]) {
id
}
}
`)
).toMatchSnapshot();
});
});

it('AND works', async () => {
await withServer(async (request) => {
expect(
await request(gql`
query AndQuery {
manyObjects(where: { xyz: 2, AND: [{ id: "${SOME_ID_2}" }] }, orderBy: [{ xyz: DESC }]) {
id
}
}
`)
).toMatchSnapshot();
});
});

it('OR works', async () => {
await withServer(async (request) => {
expect(
await request(gql`
query OrQuery {
manyObjects(where: { OR: [{ id: "${SOME_ID}" }, { id: "${SOME_ID_2}"}] }, orderBy: [{ xyz: DESC }]) {
id
}
}
`)
).toMatchSnapshot();
});
});
});
22 changes: 22 additions & 0 deletions tests/generated/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ export type AnotherObjectOrderBy = {
};

export type AnotherObjectWhere = {
AND?: InputMaybe<Array<AnotherObjectWhere>>;
NOT?: InputMaybe<AnotherObjectWhere>;
OR?: InputMaybe<Array<AnotherObjectWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
manyObjects_NONE?: InputMaybe<SomeObjectWhere>;
Expand Down Expand Up @@ -122,6 +125,9 @@ export type AnswerOrderBy = {
};

export type AnswerWhere = {
AND?: InputMaybe<Array<AnswerWhere>>;
NOT?: InputMaybe<AnswerWhere>;
OR?: InputMaybe<Array<AnswerWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
};
Expand Down Expand Up @@ -421,6 +427,9 @@ export type QuestionOrderBy = {
};

export type QuestionWhere = {
AND?: InputMaybe<Array<QuestionWhere>>;
NOT?: InputMaybe<QuestionWhere>;
OR?: InputMaybe<Array<QuestionWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
};
Expand Down Expand Up @@ -492,6 +501,9 @@ export enum ReactionType {
}

export type ReactionWhere = {
AND?: InputMaybe<Array<ReactionWhere>>;
NOT?: InputMaybe<ReactionWhere>;
OR?: InputMaybe<Array<ReactionWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
};
Expand Down Expand Up @@ -559,6 +571,9 @@ export type ReviewOrderBy = {
};

export type ReviewWhere = {
AND?: InputMaybe<Array<ReviewWhere>>;
NOT?: InputMaybe<ReviewWhere>;
OR?: InputMaybe<Array<ReviewWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
rating_GT?: InputMaybe<Scalars['Float']['input']>;
Expand Down Expand Up @@ -612,10 +627,14 @@ export type SomeObjectOrderBy = {
};

export type SomeObjectWhere = {
AND?: InputMaybe<Array<SomeObjectWhere>>;
NOT?: InputMaybe<SomeObjectWhere>;
OR?: InputMaybe<Array<SomeObjectWhere>>;
another?: InputMaybe<AnotherObjectWhere>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
float?: InputMaybe<Array<Scalars['Float']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
xyz?: InputMaybe<Array<Scalars['Int']['input']>>;
};

export type SomeObjectWhereUnique = {
Expand Down Expand Up @@ -800,6 +819,9 @@ export type UserUpdatedReviewsArgs = {
};

export type UserWhere = {
AND?: InputMaybe<Array<UserWhere>>;
NOT?: InputMaybe<UserWhere>;
OR?: InputMaybe<Array<UserWhere>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
};

Expand Down
55 changes: 55 additions & 0 deletions tests/generated/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ export type AnotherObjectOrderBy = {
};

export type AnotherObjectWhere = {
AND?: InputMaybe<Array<AnotherObjectWhere>>;
NOT?: InputMaybe<AnotherObjectWhere>;
OR?: InputMaybe<Array<AnotherObjectWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
manyObjects_NONE?: InputMaybe<SomeObjectWhere>;
Expand Down Expand Up @@ -119,6 +122,9 @@ export type AnswerOrderBy = {
};

export type AnswerWhere = {
AND?: InputMaybe<Array<AnswerWhere>>;
NOT?: InputMaybe<AnswerWhere>;
OR?: InputMaybe<Array<AnswerWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
};
Expand Down Expand Up @@ -418,6 +424,9 @@ export type QuestionOrderBy = {
};

export type QuestionWhere = {
AND?: InputMaybe<Array<QuestionWhere>>;
NOT?: InputMaybe<QuestionWhere>;
OR?: InputMaybe<Array<QuestionWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
};
Expand Down Expand Up @@ -489,6 +498,9 @@ export enum ReactionType {
}

export type ReactionWhere = {
AND?: InputMaybe<Array<ReactionWhere>>;
NOT?: InputMaybe<ReactionWhere>;
OR?: InputMaybe<Array<ReactionWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
};
Expand Down Expand Up @@ -556,6 +568,9 @@ export type ReviewOrderBy = {
};

export type ReviewWhere = {
AND?: InputMaybe<Array<ReviewWhere>>;
NOT?: InputMaybe<ReviewWhere>;
OR?: InputMaybe<Array<ReviewWhere>>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
rating_GT?: InputMaybe<Scalars['Float']['input']>;
Expand Down Expand Up @@ -609,10 +624,14 @@ export type SomeObjectOrderBy = {
};

export type SomeObjectWhere = {
AND?: InputMaybe<Array<SomeObjectWhere>>;
NOT?: InputMaybe<SomeObjectWhere>;
OR?: InputMaybe<Array<SomeObjectWhere>>;
another?: InputMaybe<AnotherObjectWhere>;
deleted?: InputMaybe<Array<Scalars['Boolean']['input']>>;
float?: InputMaybe<Array<Scalars['Float']['input']>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
xyz?: InputMaybe<Array<Scalars['Int']['input']>>;
};

export type SomeObjectWhereUnique = {
Expand Down Expand Up @@ -797,6 +816,9 @@ export type UserupdatedReviewsArgs = {
};

export type UserWhere = {
AND?: InputMaybe<Array<UserWhere>>;
NOT?: InputMaybe<UserWhere>;
OR?: InputMaybe<Array<UserWhere>>;
id?: InputMaybe<Array<Scalars['ID']['input']>>;
};

Expand Down Expand Up @@ -859,6 +881,21 @@ export type ReverseFiltersQueryQueryVariables = Exact<{ [key: string]: never; }>

export type ReverseFiltersQueryQuery = { all: Array<{ __typename: 'AnotherObject', id: string, manyObjects: Array<{ __typename: 'SomeObject', float: number }> }>, withFloat0: Array<{ __typename: 'AnotherObject', id: string, manyObjects: Array<{ __typename: 'SomeObject', float: number }> }>, withFloat0_5: Array<{ __typename: 'AnotherObject', id: string, manyObjects: Array<{ __typename: 'SomeObject', float: number }> }>, noneFloat0: Array<{ __typename: 'AnotherObject', id: string, manyObjects: Array<{ __typename: 'SomeObject', float: number }> }>, noneFloat0_5: Array<{ __typename: 'AnotherObject', id: string, manyObjects: Array<{ __typename: 'SomeObject', float: number }> }>, noneFloat2: Array<{ __typename: 'AnotherObject', id: string, manyObjects: Array<{ __typename: 'SomeObject', float: number }> }> };

export type NotQueryQueryVariables = Exact<{ [key: string]: never; }>;


export type NotQueryQuery = { manyObjects: Array<{ __typename: 'SomeObject', id: string }> };

export type AndQueryQueryVariables = Exact<{ [key: string]: never; }>;


export type AndQueryQuery = { manyObjects: Array<{ __typename: 'SomeObject', id: string }> };

export type OrQueryQueryVariables = Exact<{ [key: string]: never; }>;


export type OrQueryQuery = { manyObjects: Array<{ __typename: 'SomeObject', id: string }> };

export type DeleteAnotherObjectMutationMutationVariables = Exact<{
id: Scalars['ID']['input'];
}>;
Expand Down Expand Up @@ -1065,6 +1102,24 @@ export namespace ReverseFiltersQuery {
export type _____manyObjects = NonNullable<(NonNullable<NonNullable<(NonNullable<ReverseFiltersQueryQuery['noneFloat2']>)[number]>['manyObjects']>)[number]>;
}

export namespace NotQuery {
export type Variables = NotQueryQueryVariables;
export type query = NotQueryQuery;
export type manyObjects = NonNullable<(NonNullable<NotQueryQuery['manyObjects']>)[number]>;
}

export namespace AndQuery {
export type Variables = AndQueryQueryVariables;
export type query = AndQueryQuery;
export type manyObjects = NonNullable<(NonNullable<AndQueryQuery['manyObjects']>)[number]>;
}

export namespace OrQuery {
export type Variables = OrQueryQueryVariables;
export type query = OrQueryQuery;
export type manyObjects = NonNullable<(NonNullable<OrQueryQuery['manyObjects']>)[number]>;
}

export namespace DeleteAnotherObjectMutation {
export type Variables = DeleteAnotherObjectMutationMutationVariables;
export type mutation = DeleteAnotherObjectMutationMutation;
Expand Down
3 changes: 2 additions & 1 deletion tests/generated/models.json
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@
"nonNull": true,
"creatable": true,
"updatable": true,
"orderable": true
"orderable": true,
"filterable": true
},
{
"name": "createdAt",
Expand Down
Loading

0 comments on commit 4d51338

Please sign in to comment.