Browse Source

Fix datasource types

pull/6300/head
mohamedsalem401 1 year ago
parent
commit
786333936c
  1. 7
      packages/core/src/data_sources/index.ts
  2. 4
      packages/core/src/data_sources/model/DataRecord.ts
  3. 49
      packages/core/src/data_sources/model/DataSource.ts
  4. 33
      packages/core/src/data_sources/types.ts
  5. 6
      packages/core/test/specs/data_sources/mutable.ts

7
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<ModuleConfig, DataSources> {
@ -68,10 +68,11 @@ export default class DataSourceManager extends ItemManagerModule<ModuleConfig, D
* ]
* });
*/
add(props: DataSourceProps, opts: AddOptions = {}) {
add<DRProps extends DataRecordProps>(props: DataSourceProps<DRProps>, opts: AddOptions = {}): DataSource<DRProps> {
const { all } = this;
props.id = props.id || this._createId();
return all.add(props, opts);
return all.add(props, opts) as DataSource<DRProps>;
}
/**

4
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<T extends DataRecordProps = DataRecordProps> ext
* // Sets 'name' property to 'newValue'
*/
set<A extends _StringKey<T>>(
attributeName: Partial<T> | A,
attributeName: DeepPartialDot<T> | A,
value?: SetOptions | T[A] | undefined,
options?: SetOptions | undefined,
): this;

49
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<DS['records']> = SingleRecordType<DS['records']>,
> extends Model<DS> {
export default class DataSource<DRProps extends DataRecordProps = DataRecordProps> extends Model<
DataSourceType<DRProps>
> {
transformers: DataSourceTransformers;
/**
@ -56,7 +53,7 @@ export default class DataSource<
return {
records: [],
transformers: {},
} as unknown as Partial<DS>;
} as unknown as DataSourceType<DRProps>;
}
/**
@ -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<DRProps>} props - Properties to initialize the data source.
* @param {DataSourceOptions} opts - Options to initialize the data source.
* @name constructor
*/
constructor(props: DataSourceProps<DS>, opts: DataSourceOptions) {
constructor(props: DataSourceProps<DRProps>, opts: DataSourceOptions) {
super(
{
...props,
records: [],
} as unknown as DS,
} as unknown as DataSourceType<DRProps>,
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<DS>);
this.set({ records: new DataRecords(records!, { dataSource: this }) } as Partial<DataSourceType<DRProps>>);
}
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<DRProps>} The collection of data records.
* @name records
*/
get records() {
return this.attributes.records as NonNullable<DS['records']>;
return this.attributes.records as NonNullable<DataRecords<DRProps>>;
}
/**
@ -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<DRProps>} dr - The data record that was added.
* @private
* @name onAdd
*/
onAdd(dr: DataRecord) {
onAdd(dr: DataRecord<DRProps>) {
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<DRProps> | 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<DataRecord | undefined>} An array of data records.
* @returns {Array<DataRecord<DRProps> | 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<DRProps> | 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<DataRecordProps>} records - An array of data record properties to set.
* @param {Array<DRProps>} records - An array of data record properties to set.
* @returns {Array<DataRecord>} An array of the added data records.
* @name setRecords
*/
setRecords(records: DR[]) {
setRecords(records: DRProps[]) {
this.records.reset([], { silent: true });
records.forEach((record) => {

33
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<DR extends DataRecordProps = DataRecordProps> extends BaseDataSource {
export interface DataSourceType<DR extends DataRecordProps> extends BaseDataSource {
records: DataRecords<DR>;
}
export interface DataSourceProps<DS extends DataSourceType = DataSourceType> extends BaseDataSource {
records?: DataRecords<ExtractRecordType<DS>> | DataRecord<ExtractRecordType<DS>>[] | ExtractRecordType<DS>[];
export interface DataSourceProps<DR extends DataRecordProps> extends BaseDataSource {
records?: DataRecords<DR> | DataRecord<DR>[] | DR[];
}
export type ExtractRecordType<T> = T extends { records: DataRecords<infer DR> } ? DR : never;
export type SingleRecordType<T> = T extends Collection<infer U> ? U : never;
export type RecordPropsType<T> = T extends DataRecord<infer U> ? 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> = T extends object
? {
[K in keyof T]: K extends string
? T[K] extends object
? `${K}` | `${K}.${DotSeparatedKeys<T[K]>}`
: `${K}`
: never;
}[keyof T]
: never;
export type DeepPartialDot<T> = {
[P in DotSeparatedKeys<T>]?: P extends `${infer K}.${infer Rest}`
? K extends keyof T
? Rest extends DotSeparatedKeys<T[K]>
? DeepPartialDot<T[K]>[Rest]
: never
: never
: P extends keyof T
? T[P]
: never;
};

6
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([

Loading…
Cancel
Save