2020-07-01 18:07:57 +00:00
|
|
|
import { Adapter } from './adapter';
|
2020-07-02 05:07:27 +00:00
|
|
|
import { Model } from './model';
|
2020-07-01 18:07:57 +00:00
|
|
|
import { ModelFactory } from './model-factory';
|
|
|
|
|
2020-09-04 18:27:34 +00:00
|
|
|
type Registry< T > = { [key: string ]: T };
|
2020-07-01 18:07:57 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The types of adapters that can be stored in the registry.
|
|
|
|
*
|
|
|
|
* @typedef AdapterTypes
|
|
|
|
* @property {string} API "api"
|
|
|
|
* @property {string} Custom "custom"
|
|
|
|
*/
|
|
|
|
export enum AdapterTypes {
|
|
|
|
API = 'api',
|
|
|
|
Custom = 'custom'
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A registry that allows for us to easily manage all of our factories and related state.
|
|
|
|
*/
|
2020-07-01 19:08:08 +00:00
|
|
|
export class ModelRegistry {
|
2020-09-04 18:27:34 +00:00
|
|
|
private readonly factories: Registry< ModelFactory< any >> = {};
|
|
|
|
private readonly adapters: { [key in AdapterTypes]: Registry< Adapter< any >> } = {
|
2020-07-01 18:07:57 +00:00
|
|
|
api: {},
|
|
|
|
custom: {},
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers a factory for the class.
|
|
|
|
*
|
|
|
|
* @param {Function} modelClass The class of model we're registering the factory for.
|
|
|
|
* @param {ModelFactory} factory The factory that we're registering.
|
|
|
|
*/
|
2020-09-04 18:27:34 +00:00
|
|
|
public registerFactory< T extends Model >( modelClass: new () => T, factory: ModelFactory< T > ): void {
|
2020-07-01 20:58:12 +00:00
|
|
|
if ( this.factories.hasOwnProperty( modelClass.name ) ) {
|
2020-07-01 18:07:57 +00:00
|
|
|
throw new Error( 'A factory of this type has already been registered for the model class.' );
|
|
|
|
}
|
|
|
|
|
2020-07-01 20:58:12 +00:00
|
|
|
this.factories[ modelClass.name ] = factory;
|
2020-07-01 18:07:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetches a factory that was registered for the class.
|
|
|
|
*
|
|
|
|
* @param {Function} modelClass The class of model for the factory we're fetching.
|
|
|
|
*/
|
2020-09-04 18:27:34 +00:00
|
|
|
public getFactory< T extends Model >( modelClass: new () => T ): ModelFactory< T > | null {
|
2020-07-01 20:58:12 +00:00
|
|
|
if ( this.factories.hasOwnProperty( modelClass.name ) ) {
|
|
|
|
return this.factories[ modelClass.name ];
|
2020-07-01 18:07:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers an adapter for the class.
|
|
|
|
*
|
|
|
|
* @param {Function} modelClass The class of model that we're registering the adapter for.
|
|
|
|
* @param {AdapterTypes} type The type of adapter that we're registering.
|
|
|
|
* @param {Adapter} adapter The adapter that we're registering.
|
|
|
|
*/
|
2020-09-04 18:27:34 +00:00
|
|
|
public registerAdapter< T extends Model >( modelClass: new () => T, type: AdapterTypes, adapter: Adapter< T > ): void {
|
2020-07-01 18:07:57 +00:00
|
|
|
if ( this.adapters[ type ].hasOwnProperty( modelClass.name ) ) {
|
|
|
|
throw new Error( 'An adapter of this type has already been registered for the model class.' );
|
|
|
|
}
|
|
|
|
|
|
|
|
this.adapters[ type ][ modelClass.name ] = adapter;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetches an adapter registered for the class.
|
|
|
|
*
|
|
|
|
* @param {Function} modelClass The class of the model for the adapter we're fetching.
|
|
|
|
* @param {AdapterTypes} type The type of adapter we're fetching.
|
|
|
|
*/
|
2020-09-04 18:27:34 +00:00
|
|
|
public getAdapter< T extends Model >( modelClass: new () => T, type: AdapterTypes ): Adapter< T > | null {
|
2020-07-01 18:07:57 +00:00
|
|
|
if ( this.adapters[ type ].hasOwnProperty( modelClass.name ) ) {
|
|
|
|
return this.adapters[ type ][ modelClass.name ];
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
2020-07-01 20:58:12 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Fetches all of the adapters of a given type from the registry.
|
|
|
|
*
|
|
|
|
* @param {AdapterTypes} type The type of adapters to fetch.
|
|
|
|
*/
|
2020-09-04 18:27:34 +00:00
|
|
|
public getAdapters( type: AdapterTypes ): Adapter< any >[] {
|
2020-07-01 20:58:12 +00:00
|
|
|
return Object.values( this.adapters[ type ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Changes the adapter a factory is using.
|
|
|
|
*
|
|
|
|
* @param {Function} modelClass The class of the model factory we're changing.
|
|
|
|
* @param {AdapterTypes} type The type of adapter to set.
|
|
|
|
*/
|
2020-09-04 18:27:34 +00:00
|
|
|
public changeFactoryAdapter< T extends Model >( modelClass: new () => T, type: AdapterTypes ): void {
|
2020-07-01 20:58:12 +00:00
|
|
|
const factory = this.getFactory( modelClass );
|
|
|
|
if ( ! factory ) {
|
|
|
|
throw new Error( 'No factory defined for this model class.' );
|
|
|
|
}
|
|
|
|
const adapter = this.getAdapter( modelClass, type );
|
|
|
|
if ( ! adapter ) {
|
|
|
|
throw new Error( 'No adapter of this type registered for this model class.' );
|
|
|
|
}
|
|
|
|
|
|
|
|
factory.setAdapter( adapter );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Changes the adapters of all factories to the given type or null if one is not registered for that type.
|
|
|
|
*
|
|
|
|
* @param {AdapterTypes} type The type of adapter to set.
|
|
|
|
*/
|
|
|
|
public changeAllFactoryAdapters( type: AdapterTypes ): void {
|
|
|
|
for ( const key in this.factories ) {
|
|
|
|
this.factories[ key ].setAdapter(
|
|
|
|
this.adapters[ type ][ key ] || null,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2020-07-01 18:07:57 +00:00
|
|
|
}
|