Browse Source

feat(core): Implement `regex` string filter for PaginatedList queries

Relates to #543
Michael Bromley 5 years ago
parent
commit
0a33441fc9

+ 4 - 23
packages/admin-ui/src/lib/core/src/common/generated-types.ts

@@ -1037,7 +1037,7 @@ export type Collection = Node & {
   filters: Array<ConfigurableOperation>;
   filters: Array<ConfigurableOperation>;
   translations: Array<CollectionTranslation>;
   translations: Array<CollectionTranslation>;
   productVariants: ProductVariantList;
   productVariants: ProductVariantList;
-  customFields?: Maybe<CollectionCustomFields>;
+  customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 
 
@@ -1075,7 +1075,7 @@ export type CreateCollectionInput = {
   parentId?: Maybe<Scalars['ID']>;
   parentId?: Maybe<Scalars['ID']>;
   filters: Array<ConfigurableOperationInput>;
   filters: Array<ConfigurableOperationInput>;
   translations: Array<CreateCollectionTranslationInput>;
   translations: Array<CreateCollectionTranslationInput>;
-  customFields?: Maybe<CreateCollectionCustomFieldsInput>;
+  customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type UpdateCollectionInput = {
 export type UpdateCollectionInput = {
@@ -1086,7 +1086,7 @@ export type UpdateCollectionInput = {
   assetIds?: Maybe<Array<Scalars['ID']>>;
   assetIds?: Maybe<Array<Scalars['ID']>>;
   filters?: Maybe<Array<ConfigurableOperationInput>>;
   filters?: Maybe<Array<ConfigurableOperationInput>>;
   translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
   translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
-  customFields?: Maybe<UpdateCollectionCustomFieldsInput>;
+  customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CountryTranslationInput = {
 export type CountryTranslationInput = {
@@ -2116,6 +2116,7 @@ export type StringOperators = {
   eq?: Maybe<Scalars['String']>;
   eq?: Maybe<Scalars['String']>;
   contains?: Maybe<Scalars['String']>;
   contains?: Maybe<Scalars['String']>;
   in?: Maybe<Array<Scalars['String']>>;
   in?: Maybe<Array<Scalars['String']>>;
+  regex?: Maybe<Scalars['String']>;
 };
 };
 
 
 export type BooleanOperators = {
 export type BooleanOperators = {
@@ -3921,8 +3922,6 @@ export type CollectionFilterParameter = {
   slug?: Maybe<StringOperators>;
   slug?: Maybe<StringOperators>;
   position?: Maybe<NumberOperators>;
   position?: Maybe<NumberOperators>;
   description?: Maybe<StringOperators>;
   description?: Maybe<StringOperators>;
-  foo?: Maybe<DateOperators>;
-  bar?: Maybe<StringOperators>;
 };
 };
 
 
 export type CollectionSortParameter = {
 export type CollectionSortParameter = {
@@ -3933,8 +3932,6 @@ export type CollectionSortParameter = {
   slug?: Maybe<SortOrder>;
   slug?: Maybe<SortOrder>;
   position?: Maybe<SortOrder>;
   position?: Maybe<SortOrder>;
   description?: Maybe<SortOrder>;
   description?: Maybe<SortOrder>;
-  foo?: Maybe<SortOrder>;
-  bar?: Maybe<SortOrder>;
 };
 };
 
 
 export type CountryFilterParameter = {
 export type CountryFilterParameter = {
@@ -4203,22 +4200,6 @@ export type HistoryEntrySortParameter = {
   updatedAt?: Maybe<SortOrder>;
   updatedAt?: Maybe<SortOrder>;
 };
 };
 
 
-export type CollectionCustomFields = {
-  __typename?: 'CollectionCustomFields';
-  foo?: Maybe<Scalars['DateTime']>;
-  bar?: Maybe<Scalars['String']>;
-};
-
-export type CreateCollectionCustomFieldsInput = {
-  foo?: Maybe<Scalars['DateTime']>;
-  bar?: Maybe<Scalars['String']>;
-};
-
-export type UpdateCollectionCustomFieldsInput = {
-  foo?: Maybe<Scalars['DateTime']>;
-  bar?: Maybe<Scalars['String']>;
-};
-
 export type CustomFields = {
 export type CustomFields = {
   __typename?: 'CustomFields';
   __typename?: 'CustomFields';
   Address: Array<CustomFieldConfig>;
   Address: Array<CustomFieldConfig>;

+ 4 - 22
packages/asset-server-plugin/e2e/graphql/generated-e2e-asset-server-plugin-types.ts

@@ -872,7 +872,7 @@ export type Collection = Node & {
     filters: Array<ConfigurableOperation>;
     filters: Array<ConfigurableOperation>;
     translations: Array<CollectionTranslation>;
     translations: Array<CollectionTranslation>;
     productVariants: ProductVariantList;
     productVariants: ProductVariantList;
-    customFields?: Maybe<CollectionCustomFields>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CollectionProductVariantsArgs = {
 export type CollectionProductVariantsArgs = {
@@ -909,7 +909,7 @@ export type CreateCollectionInput = {
     parentId?: Maybe<Scalars['ID']>;
     parentId?: Maybe<Scalars['ID']>;
     filters: Array<ConfigurableOperationInput>;
     filters: Array<ConfigurableOperationInput>;
     translations: Array<CreateCollectionTranslationInput>;
     translations: Array<CreateCollectionTranslationInput>;
-    customFields?: Maybe<CreateCollectionCustomFieldsInput>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type UpdateCollectionInput = {
 export type UpdateCollectionInput = {
@@ -920,7 +920,7 @@ export type UpdateCollectionInput = {
     assetIds?: Maybe<Array<Scalars['ID']>>;
     assetIds?: Maybe<Array<Scalars['ID']>>;
     filters?: Maybe<Array<ConfigurableOperationInput>>;
     filters?: Maybe<Array<ConfigurableOperationInput>>;
     translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
     translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
-    customFields?: Maybe<UpdateCollectionCustomFieldsInput>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CountryTranslationInput = {
 export type CountryTranslationInput = {
@@ -1928,6 +1928,7 @@ export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
     eq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
     in?: Maybe<Array<Scalars['String']>>;
+    regex?: Maybe<Scalars['String']>;
 };
 };
 
 
 export type BooleanOperators = {
 export type BooleanOperators = {
@@ -3661,8 +3662,6 @@ export type CollectionFilterParameter = {
     slug?: Maybe<StringOperators>;
     slug?: Maybe<StringOperators>;
     position?: Maybe<NumberOperators>;
     position?: Maybe<NumberOperators>;
     description?: Maybe<StringOperators>;
     description?: Maybe<StringOperators>;
-    foo?: Maybe<DateOperators>;
-    bar?: Maybe<StringOperators>;
 };
 };
 
 
 export type CollectionSortParameter = {
 export type CollectionSortParameter = {
@@ -3673,8 +3672,6 @@ export type CollectionSortParameter = {
     slug?: Maybe<SortOrder>;
     slug?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
-    foo?: Maybe<SortOrder>;
-    bar?: Maybe<SortOrder>;
 };
 };
 
 
 export type CountryFilterParameter = {
 export type CountryFilterParameter = {
@@ -3943,21 +3940,6 @@ export type HistoryEntrySortParameter = {
     updatedAt?: Maybe<SortOrder>;
     updatedAt?: Maybe<SortOrder>;
 };
 };
 
 
-export type CollectionCustomFields = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
-export type CreateCollectionCustomFieldsInput = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
-export type UpdateCollectionCustomFieldsInput = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
 export type CustomFields = {
 export type CustomFields = {
     Address: Array<CustomFieldConfig>;
     Address: Array<CustomFieldConfig>;
     Collection: Array<CustomFieldConfig>;
     Collection: Array<CustomFieldConfig>;

+ 2 - 11
packages/common/src/generated-shop-types.ts

@@ -485,6 +485,7 @@ export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
     eq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
     in?: Maybe<Array<Scalars['String']>>;
+    regex?: Maybe<Scalars['String']>;
 };
 };
 
 
 export type BooleanOperators = {
 export type BooleanOperators = {
@@ -1773,7 +1774,7 @@ export type Collection = Node & {
     filters: Array<ConfigurableOperation>;
     filters: Array<ConfigurableOperation>;
     translations: Array<CollectionTranslation>;
     translations: Array<CollectionTranslation>;
     productVariants: ProductVariantList;
     productVariants: ProductVariantList;
-    customFields?: Maybe<CollectionCustomFields>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CollectionProductVariantsArgs = {
 export type CollectionProductVariantsArgs = {
@@ -2635,8 +2636,6 @@ export type CollectionFilterParameter = {
     slug?: Maybe<StringOperators>;
     slug?: Maybe<StringOperators>;
     position?: Maybe<NumberOperators>;
     position?: Maybe<NumberOperators>;
     description?: Maybe<StringOperators>;
     description?: Maybe<StringOperators>;
-    foo?: Maybe<DateOperators>;
-    bar?: Maybe<StringOperators>;
 };
 };
 
 
 export type CollectionSortParameter = {
 export type CollectionSortParameter = {
@@ -2647,8 +2646,6 @@ export type CollectionSortParameter = {
     slug?: Maybe<SortOrder>;
     slug?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
-    foo?: Maybe<SortOrder>;
-    bar?: Maybe<SortOrder>;
 };
 };
 
 
 export type ProductFilterParameter = {
 export type ProductFilterParameter = {
@@ -2761,12 +2758,6 @@ export type UpdateOrderInput = {
     customFields?: Maybe<Scalars['JSON']>;
     customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
-export type CollectionCustomFields = {
-    __typename?: 'CollectionCustomFields';
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
 export type CustomFields = {
 export type CustomFields = {
     __typename?: 'CustomFields';
     __typename?: 'CustomFields';
     Address: Array<CustomFieldConfig>;
     Address: Array<CustomFieldConfig>;

+ 4 - 23
packages/common/src/generated-types.ts

@@ -1006,7 +1006,7 @@ export type Collection = Node & {
   filters: Array<ConfigurableOperation>;
   filters: Array<ConfigurableOperation>;
   translations: Array<CollectionTranslation>;
   translations: Array<CollectionTranslation>;
   productVariants: ProductVariantList;
   productVariants: ProductVariantList;
-  customFields?: Maybe<CollectionCustomFields>;
+  customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 
 
@@ -1044,7 +1044,7 @@ export type CreateCollectionInput = {
   parentId?: Maybe<Scalars['ID']>;
   parentId?: Maybe<Scalars['ID']>;
   filters: Array<ConfigurableOperationInput>;
   filters: Array<ConfigurableOperationInput>;
   translations: Array<CreateCollectionTranslationInput>;
   translations: Array<CreateCollectionTranslationInput>;
-  customFields?: Maybe<CreateCollectionCustomFieldsInput>;
+  customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type UpdateCollectionInput = {
 export type UpdateCollectionInput = {
@@ -1055,7 +1055,7 @@ export type UpdateCollectionInput = {
   assetIds?: Maybe<Array<Scalars['ID']>>;
   assetIds?: Maybe<Array<Scalars['ID']>>;
   filters?: Maybe<Array<ConfigurableOperationInput>>;
   filters?: Maybe<Array<ConfigurableOperationInput>>;
   translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
   translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
-  customFields?: Maybe<UpdateCollectionCustomFieldsInput>;
+  customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CountryTranslationInput = {
 export type CountryTranslationInput = {
@@ -2084,6 +2084,7 @@ export type StringOperators = {
   eq?: Maybe<Scalars['String']>;
   eq?: Maybe<Scalars['String']>;
   contains?: Maybe<Scalars['String']>;
   contains?: Maybe<Scalars['String']>;
   in?: Maybe<Array<Scalars['String']>>;
   in?: Maybe<Array<Scalars['String']>>;
+  regex?: Maybe<Scalars['String']>;
 };
 };
 
 
 export type BooleanOperators = {
 export type BooleanOperators = {
@@ -3889,8 +3890,6 @@ export type CollectionFilterParameter = {
   slug?: Maybe<StringOperators>;
   slug?: Maybe<StringOperators>;
   position?: Maybe<NumberOperators>;
   position?: Maybe<NumberOperators>;
   description?: Maybe<StringOperators>;
   description?: Maybe<StringOperators>;
-  foo?: Maybe<DateOperators>;
-  bar?: Maybe<StringOperators>;
 };
 };
 
 
 export type CollectionSortParameter = {
 export type CollectionSortParameter = {
@@ -3901,8 +3900,6 @@ export type CollectionSortParameter = {
   slug?: Maybe<SortOrder>;
   slug?: Maybe<SortOrder>;
   position?: Maybe<SortOrder>;
   position?: Maybe<SortOrder>;
   description?: Maybe<SortOrder>;
   description?: Maybe<SortOrder>;
-  foo?: Maybe<SortOrder>;
-  bar?: Maybe<SortOrder>;
 };
 };
 
 
 export type CountryFilterParameter = {
 export type CountryFilterParameter = {
@@ -4171,22 +4168,6 @@ export type HistoryEntrySortParameter = {
   updatedAt?: Maybe<SortOrder>;
   updatedAt?: Maybe<SortOrder>;
 };
 };
 
 
-export type CollectionCustomFields = {
-  __typename?: 'CollectionCustomFields';
-  foo?: Maybe<Scalars['DateTime']>;
-  bar?: Maybe<Scalars['String']>;
-};
-
-export type CreateCollectionCustomFieldsInput = {
-  foo?: Maybe<Scalars['DateTime']>;
-  bar?: Maybe<Scalars['String']>;
-};
-
-export type UpdateCollectionCustomFieldsInput = {
-  foo?: Maybe<Scalars['DateTime']>;
-  bar?: Maybe<Scalars['String']>;
-};
-
 export type CustomFields = {
 export type CustomFields = {
   __typename?: 'CustomFields';
   __typename?: 'CustomFields';
   Address: Array<CustomFieldConfig>;
   Address: Array<CustomFieldConfig>;

+ 4 - 22
packages/core/e2e/graphql/generated-e2e-admin-types.ts

@@ -872,7 +872,7 @@ export type Collection = Node & {
     filters: Array<ConfigurableOperation>;
     filters: Array<ConfigurableOperation>;
     translations: Array<CollectionTranslation>;
     translations: Array<CollectionTranslation>;
     productVariants: ProductVariantList;
     productVariants: ProductVariantList;
-    customFields?: Maybe<CollectionCustomFields>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CollectionProductVariantsArgs = {
 export type CollectionProductVariantsArgs = {
@@ -909,7 +909,7 @@ export type CreateCollectionInput = {
     parentId?: Maybe<Scalars['ID']>;
     parentId?: Maybe<Scalars['ID']>;
     filters: Array<ConfigurableOperationInput>;
     filters: Array<ConfigurableOperationInput>;
     translations: Array<CreateCollectionTranslationInput>;
     translations: Array<CreateCollectionTranslationInput>;
-    customFields?: Maybe<CreateCollectionCustomFieldsInput>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type UpdateCollectionInput = {
 export type UpdateCollectionInput = {
@@ -920,7 +920,7 @@ export type UpdateCollectionInput = {
     assetIds?: Maybe<Array<Scalars['ID']>>;
     assetIds?: Maybe<Array<Scalars['ID']>>;
     filters?: Maybe<Array<ConfigurableOperationInput>>;
     filters?: Maybe<Array<ConfigurableOperationInput>>;
     translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
     translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
-    customFields?: Maybe<UpdateCollectionCustomFieldsInput>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CountryTranslationInput = {
 export type CountryTranslationInput = {
@@ -1928,6 +1928,7 @@ export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
     eq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
     in?: Maybe<Array<Scalars['String']>>;
+    regex?: Maybe<Scalars['String']>;
 };
 };
 
 
 export type BooleanOperators = {
 export type BooleanOperators = {
@@ -3661,8 +3662,6 @@ export type CollectionFilterParameter = {
     slug?: Maybe<StringOperators>;
     slug?: Maybe<StringOperators>;
     position?: Maybe<NumberOperators>;
     position?: Maybe<NumberOperators>;
     description?: Maybe<StringOperators>;
     description?: Maybe<StringOperators>;
-    foo?: Maybe<DateOperators>;
-    bar?: Maybe<StringOperators>;
 };
 };
 
 
 export type CollectionSortParameter = {
 export type CollectionSortParameter = {
@@ -3673,8 +3672,6 @@ export type CollectionSortParameter = {
     slug?: Maybe<SortOrder>;
     slug?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
-    foo?: Maybe<SortOrder>;
-    bar?: Maybe<SortOrder>;
 };
 };
 
 
 export type CountryFilterParameter = {
 export type CountryFilterParameter = {
@@ -3943,21 +3940,6 @@ export type HistoryEntrySortParameter = {
     updatedAt?: Maybe<SortOrder>;
     updatedAt?: Maybe<SortOrder>;
 };
 };
 
 
-export type CollectionCustomFields = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
-export type CreateCollectionCustomFieldsInput = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
-export type UpdateCollectionCustomFieldsInput = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
 export type CustomFields = {
 export type CustomFields = {
     Address: Array<CustomFieldConfig>;
     Address: Array<CustomFieldConfig>;
     Collection: Array<CustomFieldConfig>;
     Collection: Array<CustomFieldConfig>;

+ 2 - 10
packages/core/e2e/graphql/generated-e2e-shop-types.ts

@@ -477,6 +477,7 @@ export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
     eq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
     in?: Maybe<Array<Scalars['String']>>;
+    regex?: Maybe<Scalars['String']>;
 };
 };
 
 
 export type BooleanOperators = {
 export type BooleanOperators = {
@@ -1721,7 +1722,7 @@ export type Collection = Node & {
     filters: Array<ConfigurableOperation>;
     filters: Array<ConfigurableOperation>;
     translations: Array<CollectionTranslation>;
     translations: Array<CollectionTranslation>;
     productVariants: ProductVariantList;
     productVariants: ProductVariantList;
-    customFields?: Maybe<CollectionCustomFields>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CollectionProductVariantsArgs = {
 export type CollectionProductVariantsArgs = {
@@ -2515,8 +2516,6 @@ export type CollectionFilterParameter = {
     slug?: Maybe<StringOperators>;
     slug?: Maybe<StringOperators>;
     position?: Maybe<NumberOperators>;
     position?: Maybe<NumberOperators>;
     description?: Maybe<StringOperators>;
     description?: Maybe<StringOperators>;
-    foo?: Maybe<DateOperators>;
-    bar?: Maybe<StringOperators>;
 };
 };
 
 
 export type CollectionSortParameter = {
 export type CollectionSortParameter = {
@@ -2527,8 +2526,6 @@ export type CollectionSortParameter = {
     slug?: Maybe<SortOrder>;
     slug?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
-    foo?: Maybe<SortOrder>;
-    bar?: Maybe<SortOrder>;
 };
 };
 
 
 export type ProductFilterParameter = {
 export type ProductFilterParameter = {
@@ -2641,11 +2638,6 @@ export type UpdateOrderInput = {
     customFields?: Maybe<Scalars['JSON']>;
     customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
-export type CollectionCustomFields = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
 export type CustomFields = {
 export type CustomFields = {
     Address: Array<CustomFieldConfig>;
     Address: Array<CustomFieldConfig>;
     Collection: Array<CustomFieldConfig>;
     Collection: Array<CustomFieldConfig>;

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

@@ -77,6 +77,78 @@ describe('ListQueryBuilder', () => {
 
 
             expect(getItemLabels(testEntities.items)).toEqual(['A', 'C']);
             expect(getItemLabels(testEntities.items)).toEqual(['A', 'C']);
         });
         });
+
+        describe('regex', () => {
+            it('simple substring', async () => {
+                const { testEntities } = await adminClient.query(GET_LIST, {
+                    options: {
+                        filter: {
+                            description: {
+                                regex: 'or',
+                            },
+                        },
+                    },
+                });
+
+                expect(getItemLabels(testEntities.items)).toEqual(['A', 'B', 'D']);
+            });
+
+            it('start of string', async () => {
+                const { testEntities } = await adminClient.query(GET_LIST, {
+                    options: {
+                        filter: {
+                            description: {
+                                regex: '^in',
+                            },
+                        },
+                    },
+                });
+
+                expect(getItemLabels(testEntities.items)).toEqual(['E']);
+            });
+
+            it('end of string', async () => {
+                const { testEntities } = await adminClient.query(GET_LIST, {
+                    options: {
+                        filter: {
+                            description: {
+                                regex: 'or$',
+                            },
+                        },
+                    },
+                });
+
+                expect(getItemLabels(testEntities.items)).toEqual(['D']);
+            });
+
+            it('alternation', async () => {
+                const { testEntities } = await adminClient.query(GET_LIST, {
+                    options: {
+                        filter: {
+                            description: {
+                                regex: 'dolor|tempor',
+                            },
+                        },
+                    },
+                });
+
+                expect(getItemLabels(testEntities.items)).toEqual(['B', 'D']);
+            });
+
+            it('complex', async () => {
+                const { testEntities } = await adminClient.query(GET_LIST, {
+                    options: {
+                        filter: {
+                            description: {
+                                regex: '(dolor|tempor)|inc[i]?d[^a]d.*nt',
+                            },
+                        },
+                    },
+                });
+
+                expect(getItemLabels(testEntities.items)).toEqual(['B', 'D', 'E']);
+            });
+        });
     });
     });
 
 
     describe('boolean filtering', () => {
     describe('boolean filtering', () => {

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

@@ -105,6 +105,7 @@ input StringOperators {
     eq: String
     eq: String
     contains: String
     contains: String
     in: [String!]
     in: [String!]
+    regex: String
 }
 }
 
 
 input BooleanOperators {
 input BooleanOperators {

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

@@ -83,6 +83,7 @@ export interface StringOperators {
     eq?: string;
     eq?: string;
     contains?: string;
     contains?: string;
     in?: string[];
     in?: string[];
+    regex?: string;
 }
 }
 
 
 export interface BooleanOperators {
 export interface BooleanOperators {

+ 28 - 2
packages/core/src/service/helpers/list-query-builder/list-query-builder.ts

@@ -1,6 +1,8 @@
-import { Injectable } from '@nestjs/common';
+import { Injectable, OnApplicationBootstrap } from '@nestjs/common';
 import { ID, Type } from '@vendure/common/lib/shared-types';
 import { ID, Type } from '@vendure/common/lib/shared-types';
 import { FindConditions, FindManyOptions, FindOneOptions, SelectQueryBuilder } from 'typeorm';
 import { FindConditions, FindManyOptions, FindOneOptions, SelectQueryBuilder } from 'typeorm';
+import { BetterSqlite3Driver } from 'typeorm/driver/better-sqlite3/BetterSqlite3Driver';
+import { SqljsDriver } from 'typeorm/driver/sqljs/SqljsDriver';
 import { FindOptionsUtils } from 'typeorm/find-options/FindOptionsUtils';
 import { FindOptionsUtils } from 'typeorm/find-options/FindOptionsUtils';
 
 
 import { RequestContext } from '../../../api/common/request-context';
 import { RequestContext } from '../../../api/common/request-context';
@@ -25,9 +27,13 @@ export type ExtendedListQueryOptions<T extends VendureEntity> = {
 };
 };
 
 
 @Injectable()
 @Injectable()
-export class ListQueryBuilder {
+export class ListQueryBuilder implements OnApplicationBootstrap {
     constructor(private connection: TransactionalConnection) {}
     constructor(private connection: TransactionalConnection) {}
 
 
+    onApplicationBootstrap(): any {
+        this.registerSQLiteRegexpFunction();
+    }
+
     /**
     /**
      * Creates and configures a SelectQueryBuilder for queries that return paginated lists of entities.
      * Creates and configures a SelectQueryBuilder for queries that return paginated lists of entities.
      */
      */
@@ -75,4 +81,24 @@ export class ListQueryBuilder {
 
 
         return qb.orderBy(sort);
         return qb.orderBy(sort);
     }
     }
+
+    /**
+     * Registers a user-defined function (for flavors of SQLite driver that support it)
+     * so that we can run regex filters on string fields.
+     */
+    private registerSQLiteRegexpFunction() {
+        const regexpFn = (pattern: string, value: string) => {
+            const result = new RegExp(`${pattern}`, 'i').test(value);
+            return result ? 1 : 0;
+        };
+        const dbType = this.connection.rawConnection.options.type;
+        if (dbType === 'better-sqlite3') {
+            const driver = this.connection.rawConnection.driver as BetterSqlite3Driver;
+            driver.databaseConnection.function('regexp', regexpFn);
+        }
+        if (dbType === 'sqljs') {
+            const driver = this.connection.rawConnection.driver as SqljsDriver;
+            driver.databaseConnection.create_function('regexp', regexpFn);
+        }
+    }
 }
 }

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

@@ -3,7 +3,7 @@ import { assertNever } from '@vendure/common/lib/shared-utils';
 import { Connection, ConnectionOptions } from 'typeorm';
 import { Connection, ConnectionOptions } from 'typeorm';
 import { DateUtils } from 'typeorm/util/DateUtils';
 import { DateUtils } from 'typeorm/util/DateUtils';
 
 
-import { UserInputError } from '../../../common/error/errors';
+import { InternalServerError, UserInputError } from '../../../common/error/errors';
 import {
 import {
     BooleanOperators,
     BooleanOperators,
     DateOperators,
     DateOperators,
@@ -87,6 +87,11 @@ function buildWhereCondition(
                 clause: `${fieldName} IN (:...arg${argIndex})`,
                 clause: `${fieldName} IN (:...arg${argIndex})`,
                 parameters: { [`arg${argIndex}`]: operand },
                 parameters: { [`arg${argIndex}`]: operand },
             };
             };
+        case 'regex':
+            return {
+                clause: getRegexpClause(fieldName, argIndex, dbType),
+                parameters: { [`arg${argIndex}`]: operand },
+            };
         case 'lt':
         case 'lt':
         case 'before':
         case 'before':
             return {
             return {
@@ -136,3 +141,29 @@ function convertDate(input: Date | string | number): string | number {
     }
     }
     return input;
     return input;
 }
 }
+
+/**
+ * Returns a valid regexp clause based on the current DB driver type.
+ */
+function getRegexpClause(fieldName: string, argIndex: number, dbType: ConnectionOptions['type']): string {
+    switch (dbType) {
+        case 'mariadb':
+        case 'mysql':
+        case 'sqljs':
+        case 'better-sqlite3':
+        case 'aurora-data-api':
+            return `${fieldName} REGEXP :arg${argIndex}`;
+        case 'postgres':
+        case 'aurora-data-api-pg':
+        case 'cockroachdb':
+            return `${fieldName} ~* :arg${argIndex}`;
+        // The node-sqlite3 driver does not support user-defined functions
+        // and therefore we are unable to define a custom regexp
+        // function. See https://github.com/mapbox/node-sqlite3/issues/140
+        case 'sqlite':
+        default:
+            throw new InternalServerError(
+                `The 'regex' filter is not available when using the '${dbType}' driver`,
+            );
+    }
+}

+ 4 - 22
packages/elasticsearch-plugin/e2e/graphql/generated-e2e-elasticsearch-plugin-types.ts

@@ -872,7 +872,7 @@ export type Collection = Node & {
     filters: Array<ConfigurableOperation>;
     filters: Array<ConfigurableOperation>;
     translations: Array<CollectionTranslation>;
     translations: Array<CollectionTranslation>;
     productVariants: ProductVariantList;
     productVariants: ProductVariantList;
-    customFields?: Maybe<CollectionCustomFields>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CollectionProductVariantsArgs = {
 export type CollectionProductVariantsArgs = {
@@ -909,7 +909,7 @@ export type CreateCollectionInput = {
     parentId?: Maybe<Scalars['ID']>;
     parentId?: Maybe<Scalars['ID']>;
     filters: Array<ConfigurableOperationInput>;
     filters: Array<ConfigurableOperationInput>;
     translations: Array<CreateCollectionTranslationInput>;
     translations: Array<CreateCollectionTranslationInput>;
-    customFields?: Maybe<CreateCollectionCustomFieldsInput>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type UpdateCollectionInput = {
 export type UpdateCollectionInput = {
@@ -920,7 +920,7 @@ export type UpdateCollectionInput = {
     assetIds?: Maybe<Array<Scalars['ID']>>;
     assetIds?: Maybe<Array<Scalars['ID']>>;
     filters?: Maybe<Array<ConfigurableOperationInput>>;
     filters?: Maybe<Array<ConfigurableOperationInput>>;
     translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
     translations?: Maybe<Array<UpdateCollectionTranslationInput>>;
-    customFields?: Maybe<UpdateCollectionCustomFieldsInput>;
+    customFields?: Maybe<Scalars['JSON']>;
 };
 };
 
 
 export type CountryTranslationInput = {
 export type CountryTranslationInput = {
@@ -1928,6 +1928,7 @@ export type StringOperators = {
     eq?: Maybe<Scalars['String']>;
     eq?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     contains?: Maybe<Scalars['String']>;
     in?: Maybe<Array<Scalars['String']>>;
     in?: Maybe<Array<Scalars['String']>>;
+    regex?: Maybe<Scalars['String']>;
 };
 };
 
 
 export type BooleanOperators = {
 export type BooleanOperators = {
@@ -3661,8 +3662,6 @@ export type CollectionFilterParameter = {
     slug?: Maybe<StringOperators>;
     slug?: Maybe<StringOperators>;
     position?: Maybe<NumberOperators>;
     position?: Maybe<NumberOperators>;
     description?: Maybe<StringOperators>;
     description?: Maybe<StringOperators>;
-    foo?: Maybe<DateOperators>;
-    bar?: Maybe<StringOperators>;
 };
 };
 
 
 export type CollectionSortParameter = {
 export type CollectionSortParameter = {
@@ -3673,8 +3672,6 @@ export type CollectionSortParameter = {
     slug?: Maybe<SortOrder>;
     slug?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     position?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
     description?: Maybe<SortOrder>;
-    foo?: Maybe<SortOrder>;
-    bar?: Maybe<SortOrder>;
 };
 };
 
 
 export type CountryFilterParameter = {
 export type CountryFilterParameter = {
@@ -3943,21 +3940,6 @@ export type HistoryEntrySortParameter = {
     updatedAt?: Maybe<SortOrder>;
     updatedAt?: Maybe<SortOrder>;
 };
 };
 
 
-export type CollectionCustomFields = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
-export type CreateCollectionCustomFieldsInput = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
-export type UpdateCollectionCustomFieldsInput = {
-    foo?: Maybe<Scalars['DateTime']>;
-    bar?: Maybe<Scalars['String']>;
-};
-
 export type CustomFields = {
 export type CustomFields = {
     Address: Array<CustomFieldConfig>;
     Address: Array<CustomFieldConfig>;
     Collection: Array<CustomFieldConfig>;
     Collection: Array<CustomFieldConfig>;

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