Merge pull request #3861 from FinnStutzenstein/interfered-generics-in-DS

Type interference for the DS
This commit is contained in:
Finn Stutzenstein 2018-09-10 10:14:07 +02:00 committed by GitHub
commit 0abd36b75c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 39 additions and 32 deletions

View File

@ -1,4 +1,4 @@
import { ModelConstructor } from '../../shared/models/base.model'; import { ModelConstructor, BaseModel } from '../../shared/models/base.model';
/** /**
* Registeres the mapping of collection strings <--> actual types. Every Model should register itself here. * Registeres the mapping of collection strings <--> actual types. Every Model should register itself here.
@ -8,14 +8,14 @@ export class CollectionStringModelMapperService {
* Mapps collection strings to model constructors. Accessed by {@method registerCollectionElement} and * Mapps collection strings to model constructors. Accessed by {@method registerCollectionElement} and
* {@method getCollectionStringType}. * {@method getCollectionStringType}.
*/ */
private static collectionStringsTypeMapping: { [collectionString: string]: ModelConstructor } = {}; private static collectionStringsTypeMapping: { [collectionString: string]: ModelConstructor<BaseModel> } = {};
/** /**
* Registers the type to the collection string * Registers the type to the collection string
* @param collectionString * @param collectionString
* @param type * @param type
*/ */
public static registerCollectionElement(collectionString: string, type: ModelConstructor) { public static registerCollectionElement(collectionString: string, type: ModelConstructor<BaseModel>) {
CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString] = type; CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString] = type;
} }
@ -23,7 +23,7 @@ export class CollectionStringModelMapperService {
* Returns the constructor of the requested collection or undefined, if it is not registered. * Returns the constructor of the requested collection or undefined, if it is not registered.
* @param collectionString the requested collection * @param collectionString the requested collection
*/ */
public static getModelConstructor(collectionString: string): ModelConstructor { public static getModelConstructor(collectionString: string): ModelConstructor<BaseModel> {
return CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString]; return CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString];
} }
@ -31,7 +31,7 @@ export class CollectionStringModelMapperService {
* Returns the collection string of a given ModelConstructor or undefined, if it is not registered. * Returns the collection string of a given ModelConstructor or undefined, if it is not registered.
* @param ctor * @param ctor
*/ */
public static getCollectionString(ctor: ModelConstructor): string { public static getCollectionString(ctor: ModelConstructor<BaseModel>): string {
return Object.keys(CollectionStringModelMapperService.collectionStringsTypeMapping).find( return Object.keys(CollectionStringModelMapperService.collectionStringsTypeMapping).find(
(collectionString: string) => { (collectionString: string) => {
return ctor === CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString]; return ctor === CollectionStringModelMapperService.collectionStringsTypeMapping[collectionString];

View File

@ -182,7 +182,7 @@ export class DataStoreService {
}); });
} }
private getCollectionString(collectionType: ModelConstructor | string): string { private getCollectionString<T extends BaseModel>(collectionType: ModelConstructor<T> | string): string {
if (typeof collectionType === 'string') { if (typeof collectionType === 'string') {
return collectionType; return collectionType;
} else { } else {
@ -197,10 +197,10 @@ export class DataStoreService {
* @param ids One ID of the BaseModel * @param ids One ID of the BaseModel
* @return The given BaseModel-subclass instance * @return The given BaseModel-subclass instance
* @example: this.DS.get(User, 1) * @example: this.DS.get(User, 1)
* @example: this.DS.get('core/countdown', 2) * @example: this.DS.get<Countdown>('core/countdown', 2)
*/ */
public get<T extends BaseModel>(collectionType: ModelConstructor | string, id: number): T { public get<T extends BaseModel>(collectionType: ModelConstructor<T> | string, id: number): T {
const collectionString = this.getCollectionString(collectionType); const collectionString = this.getCollectionString<T>(collectionType);
const collection: ModelCollection = this.modelStore[collectionString]; const collection: ModelCollection = this.modelStore[collectionString];
if (!collection) { if (!collection) {
@ -211,14 +211,16 @@ export class DataStoreService {
} }
/** /**
* Read multiple ID's from dataStore * Read multiple ID's from dataStore.
*
* @param collectionType The desired BaseModel or collectionString to be read from the dataStore * @param collectionType The desired BaseModel or collectionString to be read from the dataStore
* @param ids Multiple IDs as a list of IDs of BaseModel * @param ids Multiple IDs as a list of IDs of BaseModel
* @return The BaseModel-list corresponding to the given ID(s) * @return The BaseModel-list corresponding to the given ID(s)
* @example: this.DS.get(User, [1,2,3,4,5]) * @example: this.DS.getMany(User, [1,2,3,4,5])
* @example: this.DS.getMany<User>('users/user', [1,2,3,4,5])
*/ */
public getMany<T extends BaseModel>(collectionType: ModelConstructor | string, ids: number[]): T[] { public getMany<T extends BaseModel>(collectionType: ModelConstructor<T> | string, ids: number[]): T[] {
const collectionString = this.getCollectionString(collectionType); const collectionString = this.getCollectionString<T>(collectionType);
const collection: ModelCollection = this.modelStore[collectionString]; const collection: ModelCollection = this.modelStore[collectionString];
if (!collection) { if (!collection) {
@ -234,12 +236,14 @@ export class DataStoreService {
/** /**
* Get all models of the given collection from the DataStore. * Get all models of the given collection from the DataStore.
*
* @param collectionType The desired BaseModel or collectionString to be read from the dataStore * @param collectionType The desired BaseModel or collectionString to be read from the dataStore
* @return The BaseModel-list of all instances of T * @return The BaseModel-list of all instances of T
* @example: this.DS.get(User) * @example: this.DS.getAll(User)
* @example: this.DS.getAll<User>('users/user')
*/ */
public getAll<T extends BaseModel>(collectionType: ModelConstructor | string): T[] { public getAll<T extends BaseModel>(collectionType: ModelConstructor<T> | string): T[] {
const collectionString = this.getCollectionString(collectionType); const collectionString = this.getCollectionString<T>(collectionType);
const collection: ModelCollection = this.modelStore[collectionString]; const collection: ModelCollection = this.modelStore[collectionString];
if (!collection) { if (!collection) {
@ -258,14 +262,15 @@ export class DataStoreService {
* @example this.DS.filter<User>(User, myUser => myUser.first_name === "Max") * @example this.DS.filter<User>(User, myUser => myUser.first_name === "Max")
*/ */
public filter<T extends BaseModel>( public filter<T extends BaseModel>(
collectionType: ModelConstructor | string, collectionType: ModelConstructor<T> | string,
callback: (model: T) => boolean callback: (model: T) => boolean
): T[] { ): T[] {
return this.getAll<T>(collectionType).filter(callback); return this.getAll<T>(collectionType).filter(callback);
} }
/** /**
* Add one or multiple models to dataStore * Add one or multiple models to dataStore.
*
* @param ...models The model(s) that shall be add use spread operator ("...") * @param ...models The model(s) that shall be add use spread operator ("...")
* @example this.DS.add(new User(1)) * @example this.DS.add(new User(1))
* @example this.DS.add((new User(2), new User(3))) * @example this.DS.add((new User(2), new User(3)))
@ -296,7 +301,8 @@ export class DataStoreService {
} }
/** /**
* removes one or multiple models from dataStore * removes one or multiple models from dataStore.
*
* @param Type The desired BaseModel type to be read from the dataStore * @param Type The desired BaseModel type to be read from the dataStore
* @param ...ids An or multiple IDs or a list of IDs of BaseModels. use spread operator ("...") for arrays * @param ...ids An or multiple IDs or a list of IDs of BaseModels. use spread operator ("...") for arrays
* @example this.DS.remove(User, myUser.id, 3, 4) * @example this.DS.remove(User, myUser.id, 3, 4)

View File

@ -140,7 +140,7 @@ export class OperatorService extends OpenSlidesComponent {
private updatePermissions(): void { private updatePermissions(): void {
this.permissions = []; this.permissions = [];
if (!this.user) { if (!this.user) {
const defaultGroup = this.DS.get('users/group', 1) as Group; const defaultGroup = this.DS.get<Group>('users/group', 1);
if (defaultGroup && defaultGroup.permissions instanceof Array) { if (defaultGroup && defaultGroup.permissions instanceof Array) {
this.permissions = defaultGroup.permissions; this.permissions = defaultGroup.permissions;
} }

View File

@ -2,8 +2,8 @@ import { OpenSlidesComponent } from 'app/openslides.component';
import { Deserializable } from './deserializable.model'; import { Deserializable } from './deserializable.model';
import { CollectionStringModelMapperService } from '../../core/services/collectionStringModelMapper.service'; import { CollectionStringModelMapperService } from '../../core/services/collectionStringModelMapper.service';
export interface ModelConstructor { export interface ModelConstructor<T extends BaseModel> {
new (...args: any[]): BaseModel; new (...args: any[]): T;
} }
/** /**

View File

@ -1,4 +1,5 @@
import { BaseModel } from '../base.model'; import { BaseModel } from '../base.model';
import { Item } from '../agenda/item';
/** /**
* Representation of a motion block. * Representation of a motion block.
@ -19,7 +20,7 @@ export class MotionBlock extends BaseModel {
} }
public getAgenda(): BaseModel | BaseModel[] { public getAgenda(): BaseModel | BaseModel[] {
return this.DS.get('agenda/item', this.agenda_item_id); return this.DS.get<Item>('agenda/item', this.agenda_item_id);
} }
} }

View File

@ -76,7 +76,7 @@ export class Motion extends BaseModel {
*/ */
public initDataStoreValues() { public initDataStoreValues() {
// check the containing Workflows in DataStore // check the containing Workflows in DataStore
const allWorkflows = this.DS.getAll<Workflow>(Workflow); const allWorkflows = this.DS.getAll(Workflow);
allWorkflows.forEach(localWorkflow => { allWorkflows.forEach(localWorkflow => {
if (localWorkflow.isStateContained(this.state_id)) { if (localWorkflow.isStateContained(this.state_id)) {
this.workflow = localWorkflow as Workflow; this.workflow = localWorkflow as Workflow;

View File

@ -34,7 +34,7 @@ export class User extends BaseModel {
} }
public get groups(): Group[] { public get groups(): Group[] {
return this.DS.getMany<Group>(Group, this.groups_id); return this.DS.getMany(Group, this.groups_id);
} }
public get full_name(): string { public get full_name(): string {

View File

@ -53,7 +53,7 @@ export class CategoryListComponent extends BaseComponent implements OnInit {
*/ */
public ngOnInit() { public ngOnInit() {
super.setTitle('Category'); super.setTitle('Category');
this.categoryArray = this.DS.getAll<Category>(Category); this.categoryArray = this.DS.getAll(Category);
this.dataSource = new MatTableDataSource(this.categoryArray); this.dataSource = new MatTableDataSource(this.categoryArray);
this.dataSource.sort = this.sort; this.dataSource.sort = this.sort;
@ -61,7 +61,7 @@ export class CategoryListComponent extends BaseComponent implements OnInit {
// The alternative approach is to put the observable as DataSource to the table // The alternative approach is to put the observable as DataSource to the table
this.DS.changeObservable.subscribe(newModel => { this.DS.changeObservable.subscribe(newModel => {
if (newModel instanceof Category) { if (newModel instanceof Category) {
this.categoryArray = this.DS.getAll<Category>(Category); this.categoryArray = this.DS.getAll(Category);
this.dataSource.data = this.categoryArray; this.dataSource.data = this.categoryArray;
} }
}); });

View File

@ -88,7 +88,7 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
// load existing motion // load existing motion
this.route.params.subscribe(params => { this.route.params.subscribe(params => {
// has the motion of the DataStore was initialized before. // has the motion of the DataStore was initialized before.
this.motion = this.DS.get(Motion, params.id) as Motion; this.motion = this.DS.get(Motion, params.id);
// Observe motion to get the motion in the parameter and also get the changes // Observe motion to get the motion in the parameter and also get the changes
this.DS.changeObservable.subscribe(newModel => { this.DS.changeObservable.subscribe(newModel => {
@ -165,7 +165,7 @@ export class MotionDetailComponent extends BaseComponent implements OnInit {
* return all Categories. * return all Categories.
*/ */
public getMotionCategories(): Category[] { public getMotionCategories(): Category[] {
return this.DS.getAll<Category>(Category); return this.DS.getAll(Category);
} }
/** /**

View File

@ -93,8 +93,8 @@ export class MotionListComponent extends BaseComponent implements OnInit {
*/ */
public ngOnInit() { public ngOnInit() {
super.setTitle('Motions'); super.setTitle('Motions');
this.workflowArray = this.DS.getAll<Workflow>(Workflow); this.workflowArray = this.DS.getAll(Workflow);
this.motionArray = this.DS.getAll<Motion>(Motion); this.motionArray = this.DS.getAll(Motion);
this.dataSource = new MatTableDataSource(this.motionArray); this.dataSource = new MatTableDataSource(this.motionArray);
this.dataSource.paginator = this.paginator; this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort; this.dataSource.sort = this.sort;
@ -103,7 +103,7 @@ export class MotionListComponent extends BaseComponent implements OnInit {
// The alternative approach is to put the observable as DataSource to the table // The alternative approach is to put the observable as DataSource to the table
this.DS.changeObservable.subscribe(newModel => { this.DS.changeObservable.subscribe(newModel => {
if (newModel instanceof Motion) { if (newModel instanceof Motion) {
this.motionArray = this.DS.getAll<Motion>(Motion); this.motionArray = this.DS.getAll(Motion);
this.dataSource.data = this.motionArray; this.dataSource.data = this.motionArray;
} }
}); });