From 786333936c95b16ede9d90eeed67092e263d852e Mon Sep 17 00:00:00 2001 From: mohamedsalem401 Date: Wed, 6 Nov 2024 14:50:19 +0200 Subject: [PATCH] Fix datasource types --- packages/core/src/data_sources/index.ts | 7 +-- .../core/src/data_sources/model/DataRecord.ts | 4 +- .../core/src/data_sources/model/DataSource.ts | 49 +++++++++---------- packages/core/src/data_sources/types.ts | 33 ++++++++++--- .../core/test/specs/data_sources/mutable.ts | 6 ++- 5 files changed, 60 insertions(+), 39 deletions(-) diff --git a/packages/core/src/data_sources/index.ts b/packages/core/src/data_sources/index.ts index 150cd76d5..11b5de277 100644 --- a/packages/core/src/data_sources/index.ts +++ b/packages/core/src/data_sources/index.ts @@ -42,7 +42,7 @@ import { get, stringToPath } from '../utils/mixins'; import DataRecord from './model/DataRecord'; import DataSource from './model/DataSource'; import DataSources from './model/DataSources'; -import { DataSourcesEvents, DataSourceProps } from './types'; +import { DataSourcesEvents, DataSourceProps, DataRecordProps } from './types'; import { Events } from 'backbone'; export default class DataSourceManager extends ItemManagerModule { @@ -68,10 +68,11 @@ export default class DataSourceManager extends ItemManagerModule(props: DataSourceProps, opts: AddOptions = {}): DataSource { const { all } = this; props.id = props.id || this._createId(); - return all.add(props, opts); + + return all.add(props, opts) as DataSource; } /** diff --git a/packages/core/src/data_sources/model/DataRecord.ts b/packages/core/src/data_sources/model/DataRecord.ts index 85ebe12a2..3c8c5fe93 100644 --- a/packages/core/src/data_sources/model/DataRecord.ts +++ b/packages/core/src/data_sources/model/DataRecord.ts @@ -25,7 +25,7 @@ import { keys } from 'underscore'; import { Model, SetOptions } from '../../common'; -import { DataRecordProps, DataSourcesEvents } from '../types'; +import { DataRecordProps, DataSourcesEvents, DeepPartialDot } from '../types'; import DataRecords from './DataRecords'; import DataSource from './DataSource'; import EditorModel from '../../editor/model/Editor'; @@ -135,7 +135,7 @@ export default class DataRecord ext * // Sets 'name' property to 'newValue' */ set>( - attributeName: Partial | A, + attributeName: DeepPartialDot | A, value?: SetOptions | T[A] | undefined, options?: SetOptions | undefined, ): this; diff --git a/packages/core/src/data_sources/model/DataSource.ts b/packages/core/src/data_sources/model/DataSource.ts index 618ee3068..4ea82ddfb 100644 --- a/packages/core/src/data_sources/model/DataSource.ts +++ b/packages/core/src/data_sources/model/DataSource.ts @@ -31,18 +31,15 @@ import { AddOptions, collectionEvents, CombinedModelConstructorOptions, Model, RemoveOptions } from '../../common'; import EditorModel from '../../editor/model/Editor'; -import { DataSourceProps } from '../types'; -import { DataSourceTransformers, DataSourceType, SingleRecordType } from '../types'; +import { DataSourceTransformers, DataSourceType, DataSourceProps, RecordPropsType, DataRecordProps } from '../types'; import DataRecord from './DataRecord'; import DataRecords from './DataRecords'; import DataSources from './DataSources'; interface DataSourceOptions extends CombinedModelConstructorOptions<{ em: EditorModel }, DataSource> {} - -export default class DataSource< - DS extends DataSourceType = DataSourceType, - DR extends SingleRecordType = SingleRecordType, -> extends Model { +export default class DataSource extends Model< + DataSourceType +> { transformers: DataSourceTransformers; /** @@ -56,7 +53,7 @@ export default class DataSource< return { records: [], transformers: {}, - } as unknown as Partial; + } as unknown as DataSourceType; } /** @@ -64,23 +61,23 @@ export default class DataSource< * It sets up the transformers and initializes the collection of records. * If the `records` property is not an instance of `DataRecords`, it will be converted into one. * - * @param {DataSourceProps} props - Properties to initialize the data source. + * @param {DataSourceProps} props - Properties to initialize the data source. * @param {DataSourceOptions} opts - Options to initialize the data source. * @name constructor */ - constructor(props: DataSourceProps, opts: DataSourceOptions) { + constructor(props: DataSourceProps, opts: DataSourceOptions) { super( { ...props, records: [], - } as unknown as DS, + } as unknown as DataSourceType, opts, ); const { records, transformers } = props; - this.transformers = transformers || {}; + this.transformers = transformers || ({} as DataSourceTransformers); if (!(records instanceof DataRecords)) { - this.set({ records: new DataRecords(records!, { dataSource: this }) } as Partial); + this.set({ records: new DataRecords(records!, { dataSource: this }) } as Partial>); } this.listenTo(this.records, 'add', this.onAdd); @@ -90,11 +87,11 @@ export default class DataSource< /** * Retrieves the collection of records associated with this data source. * - * @returns {DataRecords} The collection of data records. + * @returns {DataRecords} The collection of data records. * @name records */ get records() { - return this.attributes.records as NonNullable; + return this.attributes.records as NonNullable>; } /** @@ -111,23 +108,23 @@ export default class DataSource< * Handles the `add` event for records in the data source. * This method triggers a change event on the newly added record. * - * @param {DataRecord} dr - The data record that was added. + * @param {DataRecord} dr - The data record that was added. * @private * @name onAdd */ - onAdd(dr: DataRecord) { + onAdd(dr: DataRecord) { dr.triggerChange(); } /** * Adds a new record to the data source. * - * @param {DataRecordProps} record - The properties of the record to add. + * @param {DRProps} record - The properties of the record to add. * @param {AddOptions} [opts] - Options to apply when adding the record. * @returns {DataRecord} The added data record. * @name addRecord */ - addRecord(record: DR, opts?: AddOptions) { + addRecord(record: DRProps, opts?: AddOptions) { return this.records.add(record, opts); } @@ -135,18 +132,18 @@ export default class DataSource< * Retrieves a record from the data source by its ID. * * @param {string | number} id - The ID of the record to retrieve. - * @returns {DataRecord | undefined} The data record, or `undefined` if no record is found with the given ID. + * @returns {DataRecord | undefined} The data record, or `undefined` if no record is found with the given ID. * @name getRecord */ getRecord(id: string | number) { - return this.records.get(id) as DR | undefined; + return this.records.get(id) as DataRecord | undefined; } /** * Retrieves all records from the data source. * Each record is processed with the `getRecord` method to apply any read transformers. * - * @returns {Array} An array of data records. + * @returns {Array | undefined>} An array of data records. * @name getRecords */ getRecords() { @@ -158,10 +155,10 @@ export default class DataSource< * * @param {string | number} id - The ID of the record to remove. * @param {RemoveOptions} [opts] - Options to apply when removing the record. - * @returns {DataRecord | undefined} The removed data record, or `undefined` if no record is found with the given ID. + * @returns {DataRecord | undefined} The removed data record, or `undefined` if no record is found with the given ID. * @name removeRecord */ - removeRecord(id: string | number, opts?: RemoveOptions): DataRecord | undefined { + removeRecord(id: string | number, opts?: RemoveOptions) { const record = this.getRecord(id); if (record?.mutable === false && !opts?.dangerously) { throw new Error('Cannot remove immutable record'); @@ -173,11 +170,11 @@ export default class DataSource< /** * Replaces the existing records in the data source with a new set of records. * - * @param {Array} records - An array of data record properties to set. + * @param {Array} records - An array of data record properties to set. * @returns {Array} An array of the added data records. * @name setRecords */ - setRecords(records: DR[]) { + setRecords(records: DRProps[]) { this.records.reset([], { silent: true }); records.forEach((record) => { diff --git a/packages/core/src/data_sources/types.ts b/packages/core/src/data_sources/types.ts index ec9508c7a..c104e88d5 100644 --- a/packages/core/src/data_sources/types.ts +++ b/packages/core/src/data_sources/types.ts @@ -17,6 +17,8 @@ export interface DataRecordProps extends ObjectAny { * Specifies if the record is mutable. Defaults to `true`. */ mutable?: boolean; + + [key: string]: any; } export interface DataVariableListener { @@ -40,15 +42,13 @@ interface BaseDataSource { */ skipFromStorage?: boolean; } -export interface DataSourceType extends BaseDataSource { +export interface DataSourceType extends BaseDataSource { records: DataRecords; } -export interface DataSourceProps extends BaseDataSource { - records?: DataRecords> | DataRecord>[] | ExtractRecordType[]; +export interface DataSourceProps extends BaseDataSource { + records?: DataRecords | DataRecord[] | DR[]; } -export type ExtractRecordType = T extends { records: DataRecords } ? DR : never; -export type SingleRecordType = T extends Collection ? U : never; - +export type RecordPropsType = T extends DataRecord ? U : never; export interface DataSourceTransformers { onRecordSetValue?: (args: { id: string | number; key: string; value: any }) => any; } @@ -93,3 +93,24 @@ export enum DataSourcesEvents { all = 'data', } /**{END_EVENTS}*/ +type DotSeparatedKeys = T extends object + ? { + [K in keyof T]: K extends string + ? T[K] extends object + ? `${K}` | `${K}.${DotSeparatedKeys}` + : `${K}` + : never; + }[keyof T] + : never; + +export type DeepPartialDot = { + [P in DotSeparatedKeys]?: P extends `${infer K}.${infer Rest}` + ? K extends keyof T + ? Rest extends DotSeparatedKeys + ? DeepPartialDot[Rest] + : never + : never + : P extends keyof T + ? T[P] + : never; +}; diff --git a/packages/core/test/specs/data_sources/mutable.ts b/packages/core/test/specs/data_sources/mutable.ts index bf3bf0948..215e03356 100644 --- a/packages/core/test/specs/data_sources/mutable.ts +++ b/packages/core/test/specs/data_sources/mutable.ts @@ -1,6 +1,7 @@ import DataSourceManager from '../../../src/data_sources'; import { setupTestEditor } from '../../common'; import EditorModel from '../../../src/editor/model/Editor'; +import { DataRecord } from '../../../src'; describe('DataSource Immutability', () => { let em: EditorModel; @@ -48,9 +49,10 @@ describe('DataSource Immutability', () => { }); test('addRecord creates an immutable record', () => { + type RecordType = { id: string; name: string; value: number; mutable: boolean }; const ds = dsm.add({ id: 'testDs4', - records: [], + records: [] as RecordType[], }); ds.addRecord({ id: 'id1', name: 'Name1', value: 100, mutable: false }); @@ -63,7 +65,7 @@ describe('DataSource Immutability', () => { test('setRecords replaces all records with immutable ones', () => { const ds = dsm.add({ id: 'testDs5', - records: [], + records: [{ id: 'id1', name: 'Name1', value: 100, mutable: false }], }); ds.setRecords([