diff --git a/docs/backend-services/graphql/GraphQL-Filtering.md b/docs/backend-services/graphql/GraphQL-Filtering.md
index 07a6b4900..d358facce 100644
--- a/docs/backend-services/graphql/GraphQL-Filtering.md
+++ b/docs/backend-services/graphql/GraphQL-Filtering.md
@@ -2,6 +2,7 @@
- [filterBy](#filterby)
- [Complex Objects](#complex-objects)
- [Extra Query Arguments](#extra-query-arguments)
+- [Override the filter query](#override-the-filter-query)
### Introduction
The implementation of a GraphQL Service requires a certain structure to follow for `Slickgrid-Universal` to work correctly (it will fail if your GraphQL Schema is any different than what is shown below).
@@ -134,3 +135,23 @@ this.gridOptions = {
}
}
```
+
+### Override the filter query
+
+Column filters may have a `Custom` Operator, that acts as a placeholder for you to define your own logic. To do so, the easiest way is to provide the `filterQueryOverride` callback in the GraphQL Options. This method will be called with `BackendServiceFilterQueryOverrideArgs` to let you decide dynamically on how the filter should be assembled.
+
+E.g. you could listen for a specific column and the active `OperatorType.custom` in order to switch the filter to an SQL LIKE search in GraphQL:
+
+> **Note** technically speaking GraphQL isn't a database query language like SQL, it's an application query language. Depending on your configuration, your GraphQL Server might already support regex querying (e.g. Hasura [_regex](https://hasura.io/docs/latest/queries/postgres/filters/text-search-operators/#_regex)) or you could add your own implementation (e.g. see this SO: https://stackoverflow.com/a/37981802/1212166). Just make sure that whatever custom operator that you want to use, is already included in your GraphQL Schema.
+```ts
+backendServiceApi: {
+ options: {
+ filterQueryOverride: ({ fieldName, columnDef, columnFilterOperator, searchValue }) => {
+ if (columnFilterOperator === OperatorType.custom && columnDef?.id === 'name') {
+ // the `operator` is a string, make sure to implement this new operator in your GraphQL Schema
+ return { field: fieldName, operator: 'Like', value: searchValue };
+ }
+ },
+ }
+}
+```
diff --git a/packages/demo/src/examples/slickgrid/example6.ts b/packages/demo/src/examples/slickgrid/example6.ts
index a1f58f3c7..43875b224 100644
--- a/packages/demo/src/examples/slickgrid/example6.ts
+++ b/packages/demo/src/examples/slickgrid/example6.ts
@@ -34,7 +34,10 @@ export class Example6 {
The (*) can be used as startsWith (ex.: "abc*" => startsWith "abc") / endsWith (ex.: "*xyz" => endsWith "xyz")
The other operators can be used on column type number for example: ">=100" (greater or equal than 100)
- You can also preload a grid with certain "presets" like Filters / Sorters / Pagination Wiki - Grid Preset
+ You can also preload a grid with certain "presets" like Filters / Sorters / Pagination Wiki - Grid Preset
+ Also note that the column Name has a filter with a custom %% operator that behaves like an SQL LIKE operator supporting % wildcards.
+ Depending on your configuration, your GraphQL Server might already support regex querying (e.g. Hasura _regex)
+ or you could add your own implementation (e.g. see this SO Question).
`;
isWithCursor = false;
@@ -77,7 +80,15 @@ export class Example6 {
sortable: true,
filterable: true,
filter: {
- model: Filters.compoundInput
+ model: Filters.compoundInput,
+ compoundOperatorList: [
+ { operator: '', desc: 'Contains' },
+ { operator: '<>', desc: 'Not Contains' },
+ { operator: '=', desc: 'Equals' },
+ { operator: '!=', desc: 'Not equal to' },
+ { operator: 'a*', desc: 'Starts With' },
+ { operator: 'Custom', desc: 'SQL Like' },
+ ],
}
},
{
@@ -137,6 +148,10 @@ export class Example6 {
i18n: this.i18n,
gridHeight: 200,
gridWidth: 900,
+ compoundOperatorAltTexts: {
+ // where '=' is any of the `OperatorString` type shown above
+ text: { 'Custom': { operatorAlt: '%%', descAlt: 'SQL Like' } },
+ },
gridMenu: {
resizeOnShowHeaderRow: true,
},
@@ -180,6 +195,16 @@ export class Example6 {
field: 'userId',
value: 123
}],
+ filterQueryOverride: ({ fieldName, columnDef, columnFilterOperator, searchValue }) => {
+ if (columnFilterOperator === OperatorType.custom && columnDef?.id === 'name') {
+ // technically speaking GraphQL isn't a database query language like SQL, it's an application query language.
+ // What that means is that GraphQL won't let you write arbitrary queries out of the box.
+ // It will only support the types of queries defined in your GraphQL schema.
+ // see this SO: https://stackoverflow.com/a/37981802/1212166
+ return { field: fieldName, operator: 'Like', value: searchValue };
+ }
+ return;
+ },
useCursor: this.isWithCursor, // sets pagination strategy, if true requires a call to setPageInfo() when graphql call returns
// when dealing with complex objects, we want to keep our field name with double quotes
// example with gender: query { users (orderBy:[{field:"gender",direction:ASC}]) {}
diff --git a/packages/demo/tsconfig.json b/packages/demo/tsconfig.json
index e3a8a8f70..cbd66d962 100644
--- a/packages/demo/tsconfig.json
+++ b/packages/demo/tsconfig.json
@@ -12,7 +12,7 @@
"noEmit": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
- "noImplicitReturns": true,
+ "noImplicitReturns": false,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
diff --git a/test/cypress/e2e/example06.cy.ts b/test/cypress/e2e/example06.cy.ts
index 18585646c..9c447d711 100644
--- a/test/cypress/e2e/example06.cy.ts
+++ b/test/cypress/e2e/example06.cy.ts
@@ -4,6 +4,9 @@ import { removeWhitespaces } from '../plugins/utilities';
const presetLowestDay = format(addDay(new Date(), -2), 'YYYY-MM-DD');
const presetHighestDay = format(addDay(new Date(), 20), 'YYYY-MM-DD');
+function removeSpaces(textS) {
+ return `${textS}`.replace(/\s+/g, '');
+}
describe('Example 6 - GraphQL Grid', () => {
it('should display Example title', () => {
@@ -295,6 +298,29 @@ describe('Example 6 - GraphQL Grid', () => {
});
});
+ it('should perform filterQueryOverride when operator "%%" is selected', () => {
+ cy.get('.search-filter.filter-name select').find('option').last().then((element) => {
+ cy.get('.search-filter.filter-name select').select(element.val());
+ });
+
+ cy.get('.search-filter.filter-name')
+ .find('input')
+ .clear()
+ .type('Jo%yn%er');
+
+ // wait for the query to finish
+ cy.get('[data-test=status]').should('contain', 'finished');
+
+ cy.get('[data-test=graphql-query-result]')
+ .should(($span) => {
+ const text = removeSpaces($span.text()); // remove all white spaces
+ expect(text).to.eq(removeSpaces(`query { users (first:30,offset:0,
+ orderBy:[{field:"name",direction:ASC}],
+ filterBy:[{field:"name",operator:Like,value:"Jo%yn%er"}],
+ locale:"en",userId:123) { totalCount, nodes { id,name,gender,company,billing{address{street,zip}},finish } } }`));
+ });
+ });
+
it('should click on Set Dynamic Filter and expect query and filters to be changed', () => {
cy.get('[data-test=set-dynamic-filter]')
.click();