diff --git a/README.md b/README.md index c2c6c37..ace4d82 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ See the [docs](https://) ## Development +``` +npm run deps +``` + ``` npm bootstrap ``` diff --git a/src/resolvers/filters.ts b/src/resolvers/filters.ts index c0ba3fb..667569b 100644 --- a/src/resolvers/filters.ts +++ b/src/resolvers/filters.ts @@ -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; diff --git a/src/schema/generate.ts b/src/schema/generate.ts index 837b536..8977bb7 100644 --- a/src/schema/generate.ts +++ b/src/schema/generate.ts @@ -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`, diff --git a/tests/api/__snapshots__/query.spec.ts.snap b/tests/api/__snapshots__/query.spec.ts.snap index 03fbe13..9bd3bd7 100644 --- a/tests/api/__snapshots__/query.spec.ts.snap +++ b/tests/api/__snapshots__/query.spec.ts.snap @@ -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": [ diff --git a/tests/api/query.spec.ts b/tests/api/query.spec.ts index 9734ed9..8db072b 100644 --- a/tests/api/query.spec.ts +++ b/tests/api/query.spec.ts @@ -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', () => { @@ -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(); + }); + }); }); diff --git a/tests/generated/api/index.ts b/tests/generated/api/index.ts index 9c34bdc..4193545 100644 --- a/tests/generated/api/index.ts +++ b/tests/generated/api/index.ts @@ -54,6 +54,9 @@ export type AnotherObjectOrderBy = { }; export type AnotherObjectWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; manyObjects_NONE?: InputMaybe; @@ -122,6 +125,9 @@ export type AnswerOrderBy = { }; export type AnswerWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; }; @@ -421,6 +427,9 @@ export type QuestionOrderBy = { }; export type QuestionWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; }; @@ -492,6 +501,9 @@ export enum ReactionType { } export type ReactionWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; }; @@ -559,6 +571,9 @@ export type ReviewOrderBy = { }; export type ReviewWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; rating_GT?: InputMaybe; @@ -612,10 +627,14 @@ export type SomeObjectOrderBy = { }; export type SomeObjectWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; another?: InputMaybe; deleted?: InputMaybe>; float?: InputMaybe>; id?: InputMaybe>; + xyz?: InputMaybe>; }; export type SomeObjectWhereUnique = { @@ -800,6 +819,9 @@ export type UserUpdatedReviewsArgs = { }; export type UserWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; id?: InputMaybe>; }; diff --git a/tests/generated/client/index.ts b/tests/generated/client/index.ts index ac2b20a..c2b9dc9 100644 --- a/tests/generated/client/index.ts +++ b/tests/generated/client/index.ts @@ -51,6 +51,9 @@ export type AnotherObjectOrderBy = { }; export type AnotherObjectWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; manyObjects_NONE?: InputMaybe; @@ -119,6 +122,9 @@ export type AnswerOrderBy = { }; export type AnswerWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; }; @@ -418,6 +424,9 @@ export type QuestionOrderBy = { }; export type QuestionWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; }; @@ -489,6 +498,9 @@ export enum ReactionType { } export type ReactionWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; }; @@ -556,6 +568,9 @@ export type ReviewOrderBy = { }; export type ReviewWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; deleted?: InputMaybe>; id?: InputMaybe>; rating_GT?: InputMaybe; @@ -609,10 +624,14 @@ export type SomeObjectOrderBy = { }; export type SomeObjectWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; another?: InputMaybe; deleted?: InputMaybe>; float?: InputMaybe>; id?: InputMaybe>; + xyz?: InputMaybe>; }; export type SomeObjectWhereUnique = { @@ -797,6 +816,9 @@ export type UserupdatedReviewsArgs = { }; export type UserWhere = { + AND?: InputMaybe>; + NOT?: InputMaybe; + OR?: InputMaybe>; id?: InputMaybe>; }; @@ -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']; }>; @@ -1065,6 +1102,24 @@ export namespace ReverseFiltersQuery { export type _____manyObjects = NonNullable<(NonNullable)[number]>['manyObjects']>)[number]>; } +export namespace NotQuery { + export type Variables = NotQueryQueryVariables; + export type query = NotQueryQuery; + export type manyObjects = NonNullable<(NonNullable)[number]>; +} + +export namespace AndQuery { + export type Variables = AndQueryQueryVariables; + export type query = AndQueryQuery; + export type manyObjects = NonNullable<(NonNullable)[number]>; +} + +export namespace OrQuery { + export type Variables = OrQueryQueryVariables; + export type query = OrQueryQuery; + export type manyObjects = NonNullable<(NonNullable)[number]>; +} + export namespace DeleteAnotherObjectMutation { export type Variables = DeleteAnotherObjectMutationMutationVariables; export type mutation = DeleteAnotherObjectMutationMutation; diff --git a/tests/generated/models.json b/tests/generated/models.json index 141561d..65bc809 100644 --- a/tests/generated/models.json +++ b/tests/generated/models.json @@ -165,7 +165,8 @@ "nonNull": true, "creatable": true, "updatable": true, - "orderable": true + "orderable": true, + "filterable": true }, { "name": "createdAt", diff --git a/tests/generated/schema.graphql b/tests/generated/schema.graphql index d67ad5b..116a29c 100644 --- a/tests/generated/schema.graphql +++ b/tests/generated/schema.graphql @@ -19,6 +19,9 @@ input AnotherObjectWhere { deleted: [Boolean!] manyObjects_SOME: SomeObjectWhere manyObjects_NONE: SomeObjectWhere + NOT: AnotherObjectWhere + AND: [AnotherObjectWhere!] + OR: [AnotherObjectWhere!] } input AnotherObjectWhereUnique { @@ -52,6 +55,9 @@ input AnswerOrderBy { input AnswerWhere { id: [ID!] deleted: [Boolean!] + NOT: AnswerWhere + AND: [AnswerWhere!] + OR: [AnswerWhere!] } input AnswerWhereUnique { @@ -145,6 +151,9 @@ input QuestionOrderBy { input QuestionWhere { id: [ID!] deleted: [Boolean!] + NOT: QuestionWhere + AND: [QuestionWhere!] + OR: [QuestionWhere!] } input QuestionWhereUnique { @@ -184,6 +193,9 @@ enum ReactionType { input ReactionWhere { id: [ID!] deleted: [Boolean!] + NOT: ReactionWhere + AND: [ReactionWhere!] + OR: [ReactionWhere!] } input ReactionWhereUnique { @@ -222,6 +234,9 @@ input ReviewWhere { rating_GTE: Float rating_LT: Float rating_LTE: Float + NOT: ReviewWhere + AND: [ReviewWhere!] + OR: [ReviewWhere!] } input ReviewWhereUnique { @@ -265,8 +280,12 @@ input SomeObjectOrderBy { input SomeObjectWhere { id: [ID!] float: [Float!] + xyz: [Int!] deleted: [Boolean!] another: AnotherObjectWhere + NOT: SomeObjectWhere + AND: [SomeObjectWhere!] + OR: [SomeObjectWhere!] } input SomeObjectWhereUnique { @@ -321,6 +340,9 @@ type User { input UserWhere { id: [ID!] + NOT: UserWhere + AND: [UserWhere!] + OR: [UserWhere!] } input UserWhereUnique { diff --git a/tests/utils/models.ts b/tests/utils/models.ts index 13c8232..a9dea7e 100644 --- a/tests/utils/models.ts +++ b/tests/utils/models.ts @@ -104,6 +104,7 @@ const modelDefinitions: ModelDefinitions = [ creatable: true, updatable: true, orderable: true, + filterable: true, }, ], },