Browse Source

feat(core): Implement negated string filter operators

Closes #571
Michael Bromley 5 years ago
parent
commit
75b5b7a201

+ 3 - 0
packages/admin-ui/src/lib/core/src/common/generated-types.ts

@@ -2141,8 +2141,11 @@ export type ErrorResult = {
 
 export type StringOperators = {
   eq?: Maybe<Scalars['String']>;
+  notEq?: Maybe<Scalars['String']>;
   contains?: Maybe<Scalars['String']>;
+  notContains?: Maybe<Scalars['String']>;
   in?: Maybe<Array<Scalars['String']>>;
+  notIn?: Maybe<Array<Scalars['String']>>;
   regex?: Maybe<Scalars['String']>;
 };
 

+ 3 - 0
packages/asset-server-plugin/e2e/graphql/generated-e2e-asset-server-plugin-types.ts

@@ -1952,8 +1952,11 @@ export type ErrorResult = {
 
 export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
+    notEq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
+    notContains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
+    notIn?: Maybe<Array<Scalars['String']>>;
     regex?: Maybe<Scalars['String']>;
 };
 

+ 3 - 0
packages/common/src/generated-shop-types.ts

@@ -483,8 +483,11 @@ export type ErrorResult = {
 
 export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
+    notEq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
+    notContains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
+    notIn?: Maybe<Array<Scalars['String']>>;
     regex?: Maybe<Scalars['String']>;
 };
 

+ 3 - 0
packages/common/src/generated-types.ts

@@ -2109,8 +2109,11 @@ export type ErrorResult = {
 
 export type StringOperators = {
   eq?: Maybe<Scalars['String']>;
+  notEq?: Maybe<Scalars['String']>;
   contains?: Maybe<Scalars['String']>;
+  notContains?: Maybe<Scalars['String']>;
   in?: Maybe<Array<Scalars['String']>>;
+  notIn?: Maybe<Array<Scalars['String']>>;
   regex?: Maybe<Scalars['String']>;
 };
 

+ 3 - 0
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -1952,8 +1952,11 @@ export type ErrorResult = {
 
 export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
+    notEq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
+    notContains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
+    notIn?: Maybe<Array<Scalars['String']>>;
     regex?: Maybe<Scalars['String']>;
 };
 

+ 3 - 0
packages/core/e2e/graphql/generated-e2e-shop-types.ts

@@ -475,8 +475,11 @@ export type ErrorResult = {
 
 export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
+    notEq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
+    notContains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
+    notIn?: Maybe<Array<Scalars['String']>>;
     regex?: Maybe<Scalars['String']>;
 };
 

+ 42 - 0
packages/core/e2e/list-query-builder.e2e-spec.ts

@@ -50,6 +50,20 @@ describe('ListQueryBuilder', () => {
             expect(getItemLabels(testEntities.items)).toEqual(['B']);
         });
 
+        it('notEq', async () => {
+            const { testEntities } = await adminClient.query(GET_LIST, {
+                options: {
+                    filter: {
+                        label: {
+                            notEq: 'B',
+                        },
+                    },
+                },
+            });
+
+            expect(getItemLabels(testEntities.items)).toEqual(['A', 'C', 'D', 'E']);
+        });
+
         it('contains', async () => {
             const { testEntities } = await adminClient.query(GET_LIST, {
                 options: {
@@ -64,6 +78,20 @@ describe('ListQueryBuilder', () => {
             expect(getItemLabels(testEntities.items)).toEqual(['C']);
         });
 
+        it('notContains', async () => {
+            const { testEntities } = await adminClient.query(GET_LIST, {
+                options: {
+                    filter: {
+                        description: {
+                            notContains: 'te',
+                        },
+                    },
+                },
+            });
+
+            expect(getItemLabels(testEntities.items)).toEqual(['A', 'B', 'E']);
+        });
+
         it('in', async () => {
             const { testEntities } = await adminClient.query(GET_LIST, {
                 options: {
@@ -78,6 +106,20 @@ describe('ListQueryBuilder', () => {
             expect(getItemLabels(testEntities.items)).toEqual(['A', 'C']);
         });
 
+        it('notIn', async () => {
+            const { testEntities } = await adminClient.query(GET_LIST, {
+                options: {
+                    filter: {
+                        label: {
+                            notIn: ['A', 'C'],
+                        },
+                    },
+                },
+            });
+
+            expect(getItemLabels(testEntities.items)).toEqual(['B', 'D', 'E']);
+        });
+
         describe('regex', () => {
             it('simple substring', async () => {
                 const { testEntities } = await adminClient.query(GET_LIST, {

+ 3 - 0
packages/core/src/api/schema/common/common-types.graphql

@@ -103,8 +103,11 @@ interface ErrorResult {
 
 input StringOperators {
     eq: String
+    notEq: String
     contains: String
+    notContains: String
     in: [String!]
+    notIn: [String!]
     regex: String
 }
 

+ 3 - 0
packages/core/src/common/types/common-types.ts

@@ -81,8 +81,11 @@ export type FilterParameter<T extends VendureEntity> = {
 
 export interface StringOperators {
     eq?: string;
+    notEq?: string;
     contains?: string;
+    notContains?: string;
     in?: string[];
+    notIn?: string[];
     regex?: string;
 }
 

+ 19 - 1
packages/core/src/service/helpers/list-query-builder/parse-filter-params.ts

@@ -76,17 +76,35 @@ function buildWhereCondition(
                 clause: `${fieldName} = :arg${argIndex}`,
                 parameters: { [`arg${argIndex}`]: convertDate(operand) },
             };
-        case 'contains':
+        case 'notEq':
+            return {
+                clause: `${fieldName} != :arg${argIndex}`,
+                parameters: { [`arg${argIndex}`]: convertDate(operand) },
+            };
+        case 'contains': {
             const LIKE = dbType === 'postgres' ? 'ILIKE' : 'LIKE';
             return {
                 clause: `${fieldName} ${LIKE} :arg${argIndex}`,
                 parameters: { [`arg${argIndex}`]: `%${operand.trim()}%` },
             };
+        }
+        case 'notContains': {
+            const LIKE = dbType === 'postgres' ? 'ILIKE' : 'LIKE';
+            return {
+                clause: `${fieldName} NOT ${LIKE} :arg${argIndex}`,
+                parameters: { [`arg${argIndex}`]: `%${operand.trim()}%` },
+            };
+        }
         case 'in':
             return {
                 clause: `${fieldName} IN (:...arg${argIndex})`,
                 parameters: { [`arg${argIndex}`]: operand },
             };
+        case 'notIn':
+            return {
+                clause: `${fieldName} NOT IN (:...arg${argIndex})`,
+                parameters: { [`arg${argIndex}`]: operand },
+            };
         case 'regex':
             return {
                 clause: getRegexpClause(fieldName, argIndex, dbType),

+ 3 - 0
packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts

@@ -1952,8 +1952,11 @@ export type ErrorResult = {
 
 export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
+    notEq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
+    notContains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
+    notIn?: Maybe<Array<Scalars['String']>>;
     regex?: Maybe<Scalars['String']>;
 };
 

File diff suppressed because it is too large
+ 0 - 0
schema-admin.json


File diff suppressed because it is too large
+ 0 - 0
schema-shop.json


Some files were not shown because too many files changed in this diff