woocommerce/tests/e2e/factories/src/framework/model-registry.ts

129 lines
4.0 KiB
TypeScript
Raw Normal View History

import { Adapter } from './adapter';
import { Model } from '../models/model';
import { ModelFactory } from './model-factory';
type Registry<T> = { [key: string ]: T };
/**
* The types of adapters that can be stored in the registry.
*
* @typedef AdapterTypes
* @property {string} API "api"
* @property {string} Database "database"
* @property {string} Custom "custom"
*/
export enum AdapterTypes {
API = 'api',
Database = 'database',
Custom = 'custom'
}
/**
* A registry that allows for us to easily manage all of our factories and related state.
*/
export class ModelRegistry {
private readonly factories: Registry<ModelFactory<any>> = {};
private readonly adapters: { [key in AdapterTypes]: Registry<Adapter<any>> } = {
api: {},
database: {},
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.
*/
public registerFactory<T extends Model>( modelClass: new () => T, factory: ModelFactory<T> ): void {
if ( this.factories.hasOwnProperty( modelClass.name ) ) {
throw new Error( 'A factory of this type has already been registered for the model class.' );
}
this.factories[ modelClass.name ] = factory;
}
/**
* Fetches a factory that was registered for the class.
*
* @param {Function} modelClass The class of model for the factory we're fetching.
*/
public getFactory<T extends Model>( modelClass: new () => T ): ModelFactory<T> | null {
if ( this.factories.hasOwnProperty( modelClass.name ) ) {
return this.factories[ modelClass.name ];
}
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.
*/
public registerAdapter<T extends Model>( modelClass: new () => T, type: AdapterTypes, adapter: Adapter<T> ): void {
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.
*/
public getAdapter<T extends Model>( modelClass: new () => T, type: AdapterTypes ): Adapter<T> | null {
if ( this.adapters[ type ].hasOwnProperty( modelClass.name ) ) {
return this.adapters[ type ][ modelClass.name ];
}
return null;
}
/**
* Fetches all of the adapters of a given type from the registry.
*
* @param {AdapterTypes} type The type of adapters to fetch.
*/
public getAdapters( type: AdapterTypes ): Adapter<any>[] {
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.
*/
public changeFactoryAdapter<T extends Model>( modelClass: new () => T, type: AdapterTypes ): void {
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,
);
}
}
}