From d6e405f8c13b818e8cae68a35f1db89c8e29c1a7 Mon Sep 17 00:00:00 2001 From: Andrey Dolzhikov Date: Wed, 22 Jan 2025 11:38:22 +0200 Subject: [PATCH 1/3] Implementation of remote operations --- .../js/__internal/core/reactive/utilities.ts | 11 ++ .../data_controller/data_controller.ts | 57 ++++++++- .../new/grid_core/data_controller/options.ts | 9 +- .../new/grid_core/data_controller/types.ts | 6 + .../new/grid_core/data_controller/utils.ts | 108 +++++++++++++++++- 5 files changed, 181 insertions(+), 10 deletions(-) diff --git a/packages/devextreme/js/__internal/core/reactive/utilities.ts b/packages/devextreme/js/__internal/core/reactive/utilities.ts index 4c1538242e2b..bc098cc2ce1c 100644 --- a/packages/devextreme/js/__internal/core/reactive/utilities.ts +++ b/packages/devextreme/js/__internal/core/reactive/utilities.ts @@ -122,6 +122,17 @@ export function effect( callback: (t1: T1, t2: T2, t3: T3, t4: T4, t5: T5) => ((() => void) | void), deps: [Subscribable, Subscribable, Subscribable, Subscribable, Subscribable] ): Subscription; +export function effect( + callback: (t1: T1, t2: T2, t3: T3, t4: T4, t5: T5, t6: T6) => ((() => void) | void), + deps: [ + Subscribable, + Subscribable, + Subscribable, + Subscribable, + Subscribable, + Subscribable, + ] +): Subscription; export function effect( callback: (...args: TArgs) => ((() => void) | void), deps: { [I in keyof TArgs]: Subscribable }, diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts index c7c2939c208a..aef4990d3b79 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts @@ -3,6 +3,7 @@ /* eslint-disable spellcheck/spell-checker */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ import type { DataSource } from '@js/common/data'; +import ArrayStore from '@js/common/data/array_store'; import type { SubsGets } from '@ts/core/reactive/index'; import { computed, effect, state, @@ -13,9 +14,15 @@ import { createPromise } from '@ts/core/utils/promise'; // import type { Change } from '../editing/types'; import { OptionsController } from '../options_controller/options_controller'; import type { DataObject, Key } from './types'; -import { normalizeDataSource, updateItemsImmutable } from './utils'; +import { + getLocalLoadOptions, + getStoreLoadOptions, + normalizeDataSource, normalizeLocalOptions, normalizeRemoteOptions, updateItemsImmutable, +} from './utils'; export class DataController { + private readonly pendingLocalOperations = {}; + private readonly loadedPromise = createPromise(); private readonly dataSourceConfiguration = this.options.oneWay('dataSource'); @@ -36,7 +43,6 @@ export class DataController { public readonly pageSize = this.options.twoWay('paging.pageSize'); - // TODO private readonly remoteOperations = this.options.oneWay('remoteOperations'); private readonly onDataErrorOccurred = this.options.action('onDataErrorOccurred'); @@ -69,6 +75,16 @@ export class DataController { [this.totalCount, this.pageSize], ); + private readonly normalizedRemoteOptions = computed( + (remoteOperations, dataSource) => normalizeRemoteOptions(remoteOperations, dataSource), + [this.remoteOperations, this.dataSource], + ); + + private readonly normalizedLocalOperations = computed( + (normalizedRemoteOperations) => normalizeLocalOptions(normalizedRemoteOperations), + [this.normalizedRemoteOptions], + ); + public static dependencies = [OptionsController] as const; constructor( @@ -87,6 +103,26 @@ export class DataController { callback({ error }); changedCallback(); }; + const customizeStoreLoadOptionsCallback = (e): void => { + const localOptions = this.normalizedLocalOperations.unreactive_get(); + this.pendingLocalOperations[e.operationId] = getLocalLoadOptions( + e.storeLoadOptions, + localOptions, + ); + e.storeLoadOptions = getStoreLoadOptions( + e.storeLoadOptions, + localOptions, + ); + }; + + const dataLoadedCallback = (e): void => { + new ArrayStore(e.data).load(this.pendingLocalOperations[e.operationId]).done((data) => { + e.data = data; + }).fail((error) => { + // @ts-expect-error + e.data = new Deferred().reject(error); + }); + }; if (dataSource.isLoaded()) { changedCallback(); @@ -95,15 +131,32 @@ export class DataController { dataSource.on('loadingChanged', loadingChangedCallback); dataSource.on('loadError', loadErrorCallback); + // @ts-expect-error + dataSource.on('customizeStoreLoadOptions', customizeStoreLoadOptionsCallback); + // @ts-expect-error + dataSource.on('customizeLoadResult', dataLoadedCallback); + return (): void => { dataSource.off('changed', changedCallback); dataSource.off('loadingChanged', loadingChangedCallback); dataSource.off('loadError', loadErrorCallback); + + // @ts-expect-error + dataSource.off('customizeStoreLoadOptions', customizeStoreLoadOptionsCallback); + // @ts-expect-error + dataSource.on('customizeLoadResult', dataLoadedCallback); }; }, [this.dataSource], ); + effect( + () => { + this.onChanged(this.dataSource.unreactive_get(), null); + }, + [this.normalizedRemoteOptions], + ); + effect( (dataSource, pageIndex, pageSize, filter, pagingEnabled) => { let someParamChanged = false; diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/options.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/options.ts index 0667209bf3d6..c44c541e4901 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/options.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/options.ts @@ -21,7 +21,7 @@ export interface Options { keyExpr?: string | string[]; onDataErrorOccurred?: Action<{ error: string }>; paging?: PagingOptions; - remoteOperations?: RemoteOperationsOptions | boolean; + remoteOperations?: RemoteOperationsOptions | boolean | 'auto'; } export const defaultOptions = { @@ -30,11 +30,6 @@ export const defaultOptions = { pageSize: 6, pageIndex: 0, }, - remoteOperations: { - filtering: false, - paging: false, - sorting: false, - summary: false, - }, + remoteOperations: 'auto', cacheEnabled: true, } satisfies Options; diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/types.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/types.ts index ceb8279bec89..8362ac938661 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/types.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/types.ts @@ -1,3 +1,9 @@ export type DataObject = Record; export type Key = unknown; export type KeyExpr = unknown; +export interface OperationOptions { + filtering?: boolean; + sorting?: boolean; + paging?: boolean; + summary?: boolean; +} diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.ts index 4fa3c0239553..5ff4a8b7b375 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.ts @@ -1,12 +1,14 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /* eslint-disable @typescript-eslint/no-explicit-any */ +import { ArrayStore, CustomStore } from '@js/common/data'; +import type { Store } from '@js/data'; import type { DataSourceLike } from '@js/data/data_source'; import DataSource from '@js/data/data_source'; import { normalizeDataSourceOptions } from '@js/data/data_source/utils'; import { applyBatch } from '@ts/data/m_array_utils'; -import type { DataObject } from './types'; +import type { DataObject, OperationOptions } from './types'; export function normalizeDataSource( dataSourceLike: DataSourceLike | null | undefined, @@ -31,6 +33,110 @@ export function normalizeDataSource( return new DataSource(normalizeDataSourceOptions(dataSourceLike, undefined)); } +function isLocalStore(store: Store): boolean { + return store instanceof ArrayStore; +} + +function isCustomStore(store): boolean { + return store instanceof CustomStore; +} + +export function normalizeRemoteOptions( + remoteOperations: boolean | object | string, + dataSource: DataSource, +): OperationOptions { + if (remoteOperations instanceof String && remoteOperations !== 'auto') { + throw new Error('Remote operations do not support any string values except \'auto\''); + } + + const disabledAllRemoteOperations = { + filtering: false, + sorting: false, + paging: false, + summary: false, + }; + if (remoteOperations === false) { + return disabledAllRemoteOperations; + } + + if (remoteOperations === 'auto') { + const store = dataSource.store(); + if (isLocalStore(store) || isCustomStore(store)) { + return disabledAllRemoteOperations; + } + return { + filtering: true, + sorting: true, + paging: true, + summary: false, + }; + } + + const enabledAllRemoteOperations = { + filtering: true, + sorting: true, + paging: true, + summary: true, + }; + if (remoteOperations === true) { + return enabledAllRemoteOperations; + } + + return remoteOperations as object; +} + +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export function getLocalLoadOptions(originOptions, localOperations) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const localLoadOptions = {} as any; + if (localOperations.sorting) { + localLoadOptions.sort = originOptions.sort; + } + if (localOperations.filtering) { + localLoadOptions.filter = originOptions.filter; + } + if (localOperations.paging) { + localLoadOptions.skip = originOptions.skip; + localLoadOptions.take = originOptions.take; + } + if (localOperations.summary) { + localLoadOptions.summary = originOptions.summary; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return localLoadOptions; +} + +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export function getStoreLoadOptions(originOptions, localOperations) { + const storeLoadOptions = originOptions; + if (localOperations.sorting) { + delete storeLoadOptions.sort; + } + if (localOperations.filtering) { + delete storeLoadOptions.filter; + } + if (localOperations.paging) { + delete storeLoadOptions.skip; + delete storeLoadOptions.take; + } + if (localOperations.summary) { + delete storeLoadOptions.summary; + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return storeLoadOptions; +} + +export function normalizeLocalOptions( + normalizedRemoteOperations: OperationOptions, +): OperationOptions { + return { + filtering: !normalizedRemoteOperations.filtering, + sorting: !normalizedRemoteOperations.sorting, + paging: !normalizedRemoteOperations.paging, + summary: !normalizedRemoteOperations.summary, + }; +} + export function updateItemsImmutable( data: DataObject[], changes: any[], From e4b95600f03862db9148bff71a57e5504c5550f3 Mon Sep 17 00:00:00 2001 From: Andrey Dolzhikov Date: Wed, 22 Jan 2025 11:44:50 +0200 Subject: [PATCH 2/3] Clean operations --- .../grids/new/grid_core/data_controller/data_controller.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts index aef4990d3b79..f7741e83b623 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts @@ -122,6 +122,7 @@ export class DataController { // @ts-expect-error e.data = new Deferred().reject(error); }); + this.pendingLocalOperations[e.operationId] = undefined; }; if (dataSource.isLoaded()) { From a58621a40ae45180e4762ff5a9e42fe15dfaf9d9 Mon Sep 17 00:00:00 2001 From: Andrey Dolzhikov Date: Fri, 24 Jan 2025 18:39:33 +0200 Subject: [PATCH 3/3] Add tests --- .../data_controller/data_controller.ts | 23 +++- .../grid_core/data_controller/options.test.ts | 87 +++++++++++++- .../grid_core/data_controller/utils.test.ts | 107 ++++++++++++++++++ .../new/grid_core/data_controller/utils.ts | 32 +++--- 4 files changed, 228 insertions(+), 21 deletions(-) create mode 100644 packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.test.ts diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts index f7741e83b623..cc15afbca825 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/data_controller.ts @@ -17,7 +17,12 @@ import type { DataObject, Key } from './types'; import { getLocalLoadOptions, getStoreLoadOptions, - normalizeDataSource, normalizeLocalOptions, normalizeRemoteOptions, updateItemsImmutable, + isCustomStore, + isLocalStore, + normalizeDataSource, + normalizeLocalOptions, + normalizeRemoteOptions, + updateItemsImmutable, } from './utils'; export class DataController { @@ -76,7 +81,10 @@ export class DataController { ); private readonly normalizedRemoteOptions = computed( - (remoteOperations, dataSource) => normalizeRemoteOptions(remoteOperations, dataSource), + (remoteOperations, dataSource) => { + const store = dataSource.store(); + return normalizeRemoteOptions(remoteOperations, isLocalStore(store), isCustomStore(store)); + }, [this.remoteOperations, this.dataSource], ); @@ -116,6 +124,10 @@ export class DataController { }; const dataLoadedCallback = (e): void => { + /* + We use Deffered here because the code below is synchronous. + customizeLoadResult callback does not support async code. + */ new ArrayStore(e.data).load(this.pendingLocalOperations[e.operationId]).done((data) => { e.data = data; }).fail((error) => { @@ -145,7 +157,7 @@ export class DataController { // @ts-expect-error dataSource.off('customizeStoreLoadOptions', customizeStoreLoadOptionsCallback); // @ts-expect-error - dataSource.on('customizeLoadResult', dataLoadedCallback); + dataSource.off('customizeLoadResult', dataLoadedCallback); }; }, [this.dataSource], @@ -153,7 +165,10 @@ export class DataController { effect( () => { - this.onChanged(this.dataSource.unreactive_get(), null); + if (this.dataSource.unreactive_get().isLoaded()) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.dataSource.unreactive_get().load(); + } }, [this.normalizedRemoteOptions], ); diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/options.test.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/options.test.ts index 6494e74ad5e9..6f8c56c63b0e 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/options.test.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/options.test.ts @@ -229,7 +229,92 @@ describe('Options', () => { }); }); - describe.skip('remoteOperations', () => { + describe('remoteOperations', () => { + const setupForRemoteOperations = ({ remoteOperations }) => { + const store = new CustomStore({ + key: 'id', + load(loadOptions) { + const data = [ + { id: 1, value: 'value 1' }, + { id: 2, value: 'value 2' }, + { id: 3, value: 'value 3' }, + ]; + + const remotePaging = loadOptions.skip === 0 && !!loadOptions.take; + if (remotePaging) { + return Promise.resolve({ + data: [data[0]], + totalCount: 1, + }); + } + + return Promise.resolve({ + data, + totalCount: data.length, + }); + }, + }); + + jest.spyOn(store, 'load'); + + const { dataController } = setup({ + remoteOperations, + dataSource: store, + paging: { + pageSize: 1, + pageIndex: 0, + }, + }); + return { store, dataController }; + }; + + it('should exclude skip and take in the store load request by default for CustomStore', async () => { + const { store, dataController } = setupForRemoteOperations({ + remoteOperations: 'auto', + }); + + await dataController.waitLoaded(); + + const items = dataController.items.unreactive_get(); + expect(items).toHaveLength(1); + + // @ts-expect-error + expect(store.load.mock.calls[0][0].skip).toBe(undefined); + // @ts-expect-error + expect(store.load.mock.calls[0][0].take).toBe(undefined); + }); + + it('should exclude skip and take in the store load request if remotePaging disabled', async () => { + const { store, dataController } = setupForRemoteOperations({ + remoteOperations: { paging: false }, + }); + + await dataController.waitLoaded(); + + const items = dataController.items.unreactive_get(); + expect(items).toHaveLength(1); + + // @ts-expect-error + expect(store.load.mock.calls[0][0].skip).toBe(undefined); + // @ts-expect-error + expect(store.load.mock.calls[0][0].take).toBe(undefined); + }); + + it('should include skip and take in the store load request if remotePaging enabled', async () => { + const { store, dataController } = setupForRemoteOperations({ + remoteOperations: { paging: true }, + }); + + await dataController.waitLoaded(); + + const items = dataController.items.unreactive_get(); + expect(items).toHaveLength(1); + + // @ts-expect-error + expect(store.load.mock.calls[0][0].skip).toBe(0); + // @ts-expect-error + expect(store.load.mock.calls[0][0].take).toBe(1); + }); }); }); diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.test.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.test.ts new file mode 100644 index 000000000000..e41275186450 --- /dev/null +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.test.ts @@ -0,0 +1,107 @@ +/* eslint-disable object-curly-newline */ +import { describe, expect } from '@jest/globals'; +import each from 'jest-each'; + +import { + getLocalLoadOptions, getStoreLoadOptions, normalizeLocalOptions, normalizeRemoteOptions, +} from './utils'; + +describe('normalizeRemoteOption', () => { + describe('with non-object arg', () => { + each` + remoteOperations | isLocalStore | isCustomStore | expectedOperationOptions + ${'auto'} | ${true} | ${true} | ${{ filtering: false, sorting: false, paging: false, summary: false }} + ${'auto'} | ${false} | ${true} | ${{ filtering: false, sorting: false, paging: false, summary: false }} + ${'auto'} | ${true} | ${false} | ${{ filtering: false, sorting: false, paging: false, summary: false }} + ${false} | ${false} | ${false} | ${{ filtering: false, sorting: false, paging: false, summary: false }} + ${true} | ${false} | ${false} | ${{ filtering: true, sorting: true, paging: true, summary: true }} + ` + .it('should calculate the operation options', ({ + remoteOperations, + isLocalStore, + isCustomStore, + + expectedOperationOptions, + }) => { + const result = normalizeRemoteOptions(remoteOperations, isLocalStore, isCustomStore); + expect(result).toEqual(expectedOperationOptions); + }); + }); + describe('with object arg', () => { + each` + remoteOperations | isLocalStore | isCustomStore | expectedOperationOptions + ${{ filtering: true, sorting: false, paging: false, summary: false }} | ${true} | ${true} | ${{ filtering: true, sorting: false, paging: false, summary: false }} + ${{ filtering: false, sorting: true, paging: false, summary: false }} | ${true} | ${true} | ${{ filtering: false, sorting: true, paging: false, summary: false }} + ${{ filtering: false, sorting: false, paging: true, summary: false }} | ${true} | ${true} | ${{ filtering: false, sorting: false, paging: true, summary: false }} + ${{ filtering: false, sorting: false, paging: false, summary: true }} | ${true} | ${true} | ${{ filtering: false, sorting: false, paging: false, summary: true }} + ` + .it('should leave the arg as is', ({ + remoteOperations, + isLocalStore, + isCustomStore, + + expectedOperationOptions, + }) => { + const result = normalizeRemoteOptions(remoteOperations, isLocalStore, isCustomStore); + expect(result).toEqual(expectedOperationOptions); + }); + }); +}); + +describe('normalizeLocalOption', () => { + each` + remoteOperations | expectedOperationOptions + ${{ filtering: true, sorting: false, paging: false, summary: false }} | ${{ filtering: false, sorting: true, paging: true, summary: true }} + ${{ filtering: false, sorting: true, paging: false, summary: false }} | ${{ filtering: true, sorting: false, paging: true, summary: true }} + ${{ filtering: false, sorting: false, paging: true, summary: false }} | ${{ filtering: true, sorting: true, paging: false, summary: true }} + ${{ filtering: false, sorting: false, paging: false, summary: true }} | ${{ filtering: true, sorting: true, paging: true, summary: false }} + + ${{ filtering: true, sorting: true, paging: true, summary: true }} | ${{ filtering: false, sorting: false, paging: false, summary: false }} + ${{ filtering: false, sorting: false, paging: false, summary: false }}| ${{ filtering: true, sorting: true, paging: true, summary: true }} + ` + .it('should invert remoteOperations', ({ + remoteOperations, + expectedOperationOptions, + }) => { + const result = normalizeLocalOptions(remoteOperations); + expect(result).toEqual(expectedOperationOptions); + }); +}); + +describe('getLocalLoadOptions', () => { + each` + originOptions | localOperations | expectedLoadOptions + ${{ filter: 'test', sort: 'asc', skip: 0, take: 20, summary: 'test' }} | ${{ filtering: true }} | ${{ filter: 'test' }} + ${{ filter: 'test', sort: 'asc', skip: 0, take: 20, summary: 'test' }} | ${{ sorting: true }} | ${{ sort: 'asc' }} + ${{ filter: 'test', sort: 'asc', skip: 0, take: 20, summary: 'test' }} | ${{ paging: true }} | ${{ skip: 0, take: 20 }} + ${{ filter: 'test', sort: 'asc', skip: 0, take: 20, summary: 'test' }} | ${{ summary: true }} | ${{ summary: 'test' }} + ` + .it('should convert local operation to load options', ({ + originOptions, + localOperations, + + expectedLoadOptions, + }) => { + const result = getLocalLoadOptions(originOptions, localOperations); + expect(result).toEqual(expectedLoadOptions); + }); +}); + +describe('getStoreLoadOptions', () => { + each` + originOptions | localOperations | expectedLoadOptions + ${{ filter: 'test', sort: 'asc', skip: 0, take: 20, summary: 'test' }} | ${{ filtering: true }} | ${{ sort: 'asc', skip: 0, take: 20, summary: 'test' }} + ${{ filter: 'test', sort: 'asc', skip: 0, take: 20, summary: 'test' }} | ${{ sorting: true }} | ${{ filter: 'test', skip: 0, take: 20, summary: 'test' }} + ${{ filter: 'test', sort: 'asc', skip: 0, take: 20, summary: 'test' }} | ${{ paging: true }} | ${{ filter: 'test', sort: 'asc', summary: 'test' }} + ${{ filter: 'test', sort: 'asc', skip: 0, take: 20, summary: 'test' }} | ${{ summary: true }} | ${{ filter: 'test', sort: 'asc', skip: 0, take: 20 }} + ` + .it('should clear local operations from load options', ({ + originOptions, + localOperations, + + expectedLoadOptions, + }) => { + const result = getStoreLoadOptions(originOptions, localOperations); + expect(result).toEqual(expectedLoadOptions); + }); +}); diff --git a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.ts b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.ts index 5ff4a8b7b375..75a3604e4010 100644 --- a/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.ts +++ b/packages/devextreme/js/__internal/grids/new/grid_core/data_controller/utils.ts @@ -33,17 +33,18 @@ export function normalizeDataSource( return new DataSource(normalizeDataSourceOptions(dataSourceLike, undefined)); } -function isLocalStore(store: Store): boolean { +export function isLocalStore(store: Store): boolean { return store instanceof ArrayStore; } -function isCustomStore(store): boolean { +export function isCustomStore(store: Store): boolean { return store instanceof CustomStore; } export function normalizeRemoteOptions( remoteOperations: boolean | object | string, - dataSource: DataSource, + localStore: boolean, + customStore: boolean, ): OperationOptions { if (remoteOperations instanceof String && remoteOperations !== 'auto') { throw new Error('Remote operations do not support any string values except \'auto\''); @@ -60,8 +61,7 @@ export function normalizeRemoteOptions( } if (remoteOperations === 'auto') { - const store = dataSource.store(); - if (isLocalStore(store) || isCustomStore(store)) { + if (localStore || customStore) { return disabledAllRemoteOperations; } return { @@ -85,6 +85,17 @@ export function normalizeRemoteOptions( return remoteOperations as object; } +export function normalizeLocalOptions( + normalizedRemoteOperations: OperationOptions, +): OperationOptions { + return { + filtering: !normalizedRemoteOperations.filtering, + sorting: !normalizedRemoteOperations.sorting, + paging: !normalizedRemoteOperations.paging, + summary: !normalizedRemoteOperations.summary, + }; +} + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type export function getLocalLoadOptions(originOptions, localOperations) { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -126,17 +137,6 @@ export function getStoreLoadOptions(originOptions, localOperations) { return storeLoadOptions; } -export function normalizeLocalOptions( - normalizedRemoteOperations: OperationOptions, -): OperationOptions { - return { - filtering: !normalizedRemoteOperations.filtering, - sorting: !normalizedRemoteOperations.sorting, - paging: !normalizedRemoteOperations.paging, - summary: !normalizedRemoteOperations.summary, - }; -} - export function updateItemsImmutable( data: DataObject[], changes: any[],