From 7b3590f323ea2fe3d3f312674205fc94485213fa Mon Sep 17 00:00:00 2001 From: Ghislain B Date: Fri, 10 Nov 2023 16:14:51 -0500 Subject: [PATCH] fix(graphql): deprecate `isWithCursor` in favor of simpler `useCursor` (#1187) * fix(graphql): deprecate `isWithCursor` in favor of simpler `useCursor` --- .github/workflows/cypress.yml | 25 ++++++++----------- .../src/examples/example10.ts | 6 ++--- .../common/src/services/pagination.service.ts | 3 ++- .../graphqlServiceOption.interface.ts | 13 ++++++---- .../__tests__/graphql.service.spec.ts | 21 ++++++++++------ .../graphql/src/services/graphql.service.ts | 16 +++++++----- 6 files changed, 47 insertions(+), 37 deletions(-) diff --git a/.github/workflows/cypress.yml b/.github/workflows/cypress.yml index b8eb93185..16869c77c 100644 --- a/.github/workflows/cypress.yml +++ b/.github/workflows/cypress.yml @@ -36,30 +36,25 @@ jobs: with: node-version: ${{ matrix.node }} - - name: Install pnpm - uses: pnpm/action-setup@v2 - with: - version: 8 - run_install: false - - - run: node --version - - run: pnpm --version - - name: Get pnpm store directory shell: bash run: | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV - - uses: actions/cache@v3 - name: Setup pnpm cache + - name: Setup pnpm cache + uses: actions/cache@v3 with: path: ${{ env.STORE_PATH }} key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm-store- - - name: Run pnpm install dependencies - run: pnpm install + - uses: pnpm/action-setup@v2 + with: + version: 8 + run_install: true + + - run: pnpm --version - name: TSC Build (esm) run: pnpm build:esm:styles @@ -68,7 +63,7 @@ jobs: run: pnpm build:dev - name: Run Cypress E2E tests - uses: cypress-io/github-action@v5 + uses: cypress-io/github-action@v6 with: install: false # working-directory: packages/dnd @@ -106,4 +101,4 @@ jobs: uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs + publish_dir: ./docs \ No newline at end of file diff --git a/examples/vite-demo-vanilla-bundle/src/examples/example10.ts b/examples/vite-demo-vanilla-bundle/src/examples/example10.ts index fbeae58bf..1eec37f2b 100644 --- a/examples/vite-demo-vanilla-bundle/src/examples/example10.ts +++ b/examples/vite-demo-vanilla-bundle/src/examples/example10.ts @@ -187,7 +187,7 @@ export default class Example10 { field: 'userId', value: 123 }], - isWithCursor: this.isWithCursor, // sets pagination strategy, if true requires a call to setPageInfo() when graphql call returns + 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}]) {} keepArgumentFieldDoubleQuotes: true @@ -345,7 +345,7 @@ export default class Example10 { setIsWithCursor(newValue: boolean) { this.isWithCursor = newValue; - this.resetOptions({ isWithCursor: this.isWithCursor }); + this.resetOptions({ useCursor: this.isWithCursor }); } async switchLanguage() { @@ -357,7 +357,7 @@ export default class Example10 { private resetOptions(options: Partial) { const graphqlService = this.gridOptions.backendServiceApi!.service as GraphqlService; - this.sgb?.paginationService!.setCursorBased(options.isWithCursor!); + this.sgb?.paginationService!.setCursorBased(options.useCursor!); this.sgb?.paginationService?.goToFirstPage(); graphqlService.updateOptions(options); this.gridOptions = { ...this.gridOptions }; diff --git a/packages/common/src/services/pagination.service.ts b/packages/common/src/services/pagination.service.ts index d1e01e0f3..4c63815b3 100644 --- a/packages/common/src/services/pagination.service.ts +++ b/packages/common/src/services/pagination.service.ts @@ -122,7 +122,8 @@ export class PaginationService { this._paginationOptions = paginationOptions; this._isLocalGrid = !backendServiceApi; this._pageNumber = paginationOptions.pageNumber || 1; - this._isCursorBased = this._backendServiceApi?.options?.isWithCursor ?? false; + const backendServOptions = backendServiceApi?.options ?? {}; + this._isCursorBased = (backendServOptions.useCursor || backendServOptions.isWithCursor); if (backendServiceApi && (!backendServiceApi.service || !backendServiceApi.process)) { throw new Error(`BackendServiceApi requires the following 2 properties "process" and "service" to be defined.`); diff --git a/packages/graphql/src/interfaces/graphqlServiceOption.interface.ts b/packages/graphql/src/interfaces/graphqlServiceOption.interface.ts index af1162c1f..bb6080ef0 100644 --- a/packages/graphql/src/interfaces/graphqlServiceOption.interface.ts +++ b/packages/graphql/src/interfaces/graphqlServiceOption.interface.ts @@ -23,15 +23,12 @@ export interface GraphqlServiceOption extends BackendServiceOption { */ extraQueryArguments?: QueryArgument[]; - /** Is the GraphQL Server using cursors? */ - isWithCursor?: boolean; + /** array of Filtering Options, ex.: { field: name, operator: EQ, value: "John" } */ + filteringOptions?: GraphqlFilteringOption[]; /** What are the pagination options? ex.: (first, last, offset) */ paginationOptions?: GraphqlPaginationOption | GraphqlCursorPaginationOption; - /** array of Filtering Options, ex.: { field: name, operator: EQ, value: "John" } */ - filteringOptions?: GraphqlFilteringOption[]; - /** array of Filtering Options, ex.: { field: name, direction: DESC } */ sortingOptions?: GraphqlSortingOption[]; @@ -41,6 +38,12 @@ export interface GraphqlServiceOption extends BackendServiceOption { */ keepArgumentFieldDoubleQuotes?: boolean; + /** @deprecated @use `useCursor` Is the GraphQL Server using cursors? */ + isWithCursor?: boolean; + + /** Use Pagination Cursor in the GraphQL Server */ + useCursor?: boolean; + /** * When false, searchTerms may be manipulated to be functional with certain filters eg: string only filters. * When true, JSON.stringify is used on the searchTerms and used in the query "as-is". It is then the responsibility of the developer to sanitise the `searchTerms` property if necessary. diff --git a/packages/graphql/src/services/__tests__/graphql.service.spec.ts b/packages/graphql/src/services/__tests__/graphql.service.spec.ts index bcaa60bf1..0627813a8 100644 --- a/packages/graphql/src/services/__tests__/graphql.service.spec.ts +++ b/packages/graphql/src/services/__tests__/graphql.service.spec.ts @@ -12,7 +12,6 @@ import { MultiColumnSort, OperatorType, Pagination, - PaginationCursorChangedArgs, SharedService, SlickGrid, TranslaterService, @@ -100,6 +99,14 @@ describe('GraphqlService', () => { expect(spy).toHaveBeenCalled(); expect(service.columnDefinitions).toEqual(columns); }); + + it('should display a console warning when using deprecated "isWithCursor" option', () => { + const consoleSpy = jest.spyOn(global.console, 'warn').mockReturnValue(); + + service.init({ datasetName: 'users', isWithCursor: true }, paginationOptions, gridStub); + + expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[Slickgrid-Universal] The option `isWithCursor` is now deprecated and was replaced by `useCursor`.')); + }); }); describe('buildQuery method', () => { @@ -203,7 +210,7 @@ describe('GraphqlService', () => { const columns = []; jest.spyOn(gridStub, 'getColumns').mockReturnValue(columns); - service.init({ datasetName: 'users', isWithCursor: true }, paginationOptions, gridStub); + service.init({ datasetName: 'users', useCursor: true }, paginationOptions, gridStub); service.updatePagination(3, 20); const query = service.buildQuery(); @@ -215,7 +222,7 @@ describe('GraphqlService', () => { const columns = [{ id: 'field1', field: 'field1', width: 100 }]; jest.spyOn(gridStub, 'getColumns').mockReturnValue(columns); - service.init({ datasetName: 'users', isWithCursor: true }, paginationOptions, gridStub); + service.init({ datasetName: 'users', useCursor: true }, paginationOptions, gridStub); service.updatePagination(3, 20); const query = service.buildQuery(); @@ -456,9 +463,9 @@ describe('GraphqlService', () => { expect(output).toEqual({ first: 20, offset: 0 }); }); - it('should return the pagination options with cursor info when "isWithCursor" is enabled', () => { + it('should return the pagination options with cursor info when "useCursor" is enabled', () => { jest.spyOn(gridStub, 'getColumns').mockReturnValue([]); - service.init({ datasetName: 'users', isWithCursor: true }, paginationOptions); + service.init({ datasetName: 'users', useCursor: true }, paginationOptions); const output = service.getInitPaginationOptions(); expect(output).toEqual({ first: 20 }); }); @@ -506,7 +513,7 @@ describe('GraphqlService', () => { const spy = jest.spyOn(service, 'updateOptions'); jest.spyOn(gridStub, 'getColumns').mockReturnValue([]); - service.init({ datasetName: 'users', isWithCursor: true }, paginationOptions); + service.init({ datasetName: 'users', useCursor: true }, paginationOptions); service.resetPaginationOptions(); expect(spy).toHaveBeenCalledWith({ paginationOptions: { first: 20 } }); @@ -638,7 +645,7 @@ describe('GraphqlService', () => { it('should return a query with the new pagination and use pagination size options that was passed to service options when it is not provided as argument to "processOnPaginationChanged"', () => { const querySpy = jest.spyOn(service, 'buildQuery'); - service.init({ ...serviceOptions, isWithCursor: true }, paginationOptions, gridStub); + service.init({ ...serviceOptions, useCursor: true }, paginationOptions, gridStub); const query = service.processOnPaginationChanged(null as any, { newPage: 3, pageSize: 20, ...cursorArgs }); const currentPagination = service.getCurrentPagination(); diff --git a/packages/graphql/src/services/graphql.service.ts b/packages/graphql/src/services/graphql.service.ts index f2bed1628..6c3fb4efa 100644 --- a/packages/graphql/src/services/graphql.service.ts +++ b/packages/graphql/src/services/graphql.service.ts @@ -72,9 +72,13 @@ export class GraphqlService implements BackendService { this.pagination = pagination; this._datasetIdPropName = this._gridOptions.datasetIdPropertyName || 'id'; - if (grid && grid.getColumns) { + if (grid?.getColumns) { this._columnDefinitions = sharedService?.allColumns ?? grid.getColumns() ?? []; } + if (this.options?.isWithCursor) { + console.warn('[Slickgrid-Universal] The option `isWithCursor` is now deprecated and was replaced by `useCursor`.'); + } + } /** @@ -117,7 +121,7 @@ export class GraphqlService implements BackendService { let graphqlNodeFields = []; if (this._gridOptions.enablePagination !== false) { - if (this.options.isWithCursor) { + if (this.options.useCursor || this.options.isWithCursor) { // ...pageInfo { hasNextPage, endCursor }, edges { cursor, node { _columns_ } }, totalCount: 100 const edgesQb = new QueryBuilder('edges'); const pageInfoQb = new QueryBuilder('pageInfo'); @@ -144,7 +148,7 @@ export class GraphqlService implements BackendService { if (this._gridOptions.enablePagination !== false) { datasetFilters = {}; - if (this.options.isWithCursor && this.options.paginationOptions) { + if ((this.options.useCursor || this.options.isWithCursor) && this.options.paginationOptions) { datasetFilters = { ...this.options.paginationOptions }; } else { @@ -225,7 +229,7 @@ export class GraphqlService implements BackendService { */ getInitPaginationOptions(): GraphqlDatasetFilter { const paginationFirst = this.pagination ? this.pagination.pageSize : DEFAULT_ITEMS_PER_PAGE; - return (this.options?.isWithCursor) ? { first: paginationFirst } : { first: paginationFirst, offset: 0 }; + return (this.options && (this.options.useCursor || this.options.isWithCursor)) ? { first: paginationFirst } : { first: paginationFirst, offset: 0 }; } /** Get the GraphQL dataset name */ @@ -254,7 +258,7 @@ export class GraphqlService implements BackendService { resetPaginationOptions() { let paginationOptions: GraphqlPaginationOption | GraphqlCursorPaginationOption; - if (this.options && this.options.isWithCursor) { + if (this.options && (this.options.useCursor || this.options.isWithCursor)) { paginationOptions = this.getInitPaginationOptions(); } else { // first, last, offset @@ -511,7 +515,7 @@ export class GraphqlService implements BackendService { }; let paginationOptions: GraphqlPaginationOption | GraphqlCursorPaginationOption = {}; - if (this.options?.isWithCursor) { + if (this.options && (this.options.useCursor || this.options.isWithCursor)) { // use cursor based pagination // when using cursor pagination, expect to be given a PaginationCursorChangedArgs as arguments, // but still handle the case where it's not (can happen when initial configuration not pre-configured (automatically corrects itself next setCursorPageInfo() call))