diff --git a/karaokatalog/ui/static/model/Base.js b/karaokatalog/ui/static/model/Base.js new file mode 100644 index 0000000..3eb974b --- /dev/null +++ b/karaokatalog/ui/static/model/Base.js @@ -0,0 +1,64 @@ +function toMap(objs) { + return new Map(objs.map(obj => [obj.id || obj.uuid, obj])) +} + +export class Base { + /** + * A Map mapping ids to instances of `Base`. + * Must be treated as private. + */ + static _byId = null + + /** + * @return A list of all instances of `Base` + */ + static get all() { + return this._byId ? Array.from(this._byId.values()) : null + } + + /** + * @param {str} id A id + * @returns The instance with the given id, if it exists + */ + static get(id) { + return this._byId ? this._byId.get(id) : null + } + + /** + * Load the objects from the API, unless the objects have already been loaded. + * They are then stored in `this.byUid`. + * + * @returns Nothing. + */ + static async load() { + if (!this._byId) { + const objects = await this.forceLoad() + // Hack: We get plain JSON objects from the server, however, we'd like + // them to actually be instances of the classes we define. So, we first create a new empty + // instance of whatever subclass of `Base` we are currently in using `new this()`, + // and then copy all properties from the plain object over to the instance + // using `Object.assign`. + const instances = objects.map(obj => Object.assign(new this(), obj)) + this._byId = toMap(instances) + } + } + + /** + * If the objects were already loaded, forget them and load them again. + * If the objects were not yet loaded, don't do anything. + */ + static refresh() { + if (this._byId) { + this._byId = null + this.load() + } + } + + /** + * Load the objects from the API and return them. + * Abstract method, must be overriden in child classes. + * + * @returns A list of instances. + */ + static async forceLoad() {} +}