import {IRepository} from '../interfaces'; import {BaseModel} from './baseModel'; import {ObjectHelper} from '../helpers'; /** * Basic Repository to Build an HTTPbased ActiveRecord */ export abstract class BaseRepository implements IRepository { private _endpoint = ''; /** * Default-Konstruktor * @param {string} endpoint */ constructor(endpoint: string) { this._endpoint = BaseRepository._replaceParams(endpoint); } /** * Get Current Endpoint * @return {string} */ public get endpoint() { return this._endpoint; } /** * Getting all Datasets without a filter * @return {Promise} */ all(): Promise { return fetch(this._endpoint).then((response) => { if (response.status === 404) { return []; } return response.json() .then((value) => (value as any[]) .sort((a, b) => b.id - a.id)); }); } /** * Searching for a String * @param {string | undefined} search * @return {Promise} */ where(search: string | undefined): Promise { return this.all() .then((data) => BaseRepository.search(data, search)); } /** * Suche mit Parametern * @param {any} params * @return {Promise} */ whereByParams(params: { [Identifier: string]: string }) : Promise { return this.all() .then((data) => BaseRepository.searchByKeys(data, params)); } /** * Destroy Entity by id * @param {number} id * @return {Promise} */ destroy(id: number): Promise { return new Promise((resolve) => { fetch(this.buildEndpointWithId(id), { method: 'DELETE', }).then((response) => { resolve(response.ok); }).catch((error) => { console.error(error); resolve(false); }); }); } /** * Find a Object by its id * @param {number} id * @return {Promise} */ find(id: number): Promise { return fetch(this.buildEndpointWithId(id)) .then((response) => { if (response.ok) { return response.json(); } else { throw Error(response.statusText); } }); } /** * Update a Entity in Backend * @param {T} model * @return {Promise} */ update(model: T): Promise { if (BaseModel.isPersisted(model)) { return new Promise((resolve) => { const id = model.id == undefined ? 0 : parseInt(model.id.toString()); fetch(this.buildEndpointWithId(id), { method: 'Update', body: JSON.stringify(model), }).then((response) => { resolve(response.ok); }).catch((response) => { console.error(response); resolve(false); }); }); } else { throw new Error('Model is not persisted!'); } } /** * Create a new Entity in Backend * @param {T} model * @return {Promise} */ create(model: T): Promise { if (!BaseModel.isPersisted(model)) { return new Promise((resolve) => { fetch(this._endpoint, { method: 'POST', body: JSON.stringify(model), }).then((response) => { resolve(response.ok); }).catch((response) => { console.error(response); resolve(false); }); }); } else { throw new Error('Model is already persisted!'); } } /** * Save automatically decides if a model should be created * or updated. The decision is based on the model id * @param {T} model * @return {Promise} */ save(model: T): Promise { if (model.persisted) { return this.create(model); } else { return this.update(model); } } /** * Build Endpoint relative URL for ID * @param {number|string} id * @return {string} */ private buildEndpointWithId(id: number | string): string { return `${this._endpoint}/${id}`; } /** * Search by Value in Array * @param {Array} data * @param {string | undefined} searchValue * @return {Array} */ static search(data: Array, searchValue: string | undefined) { if (searchValue) { return data.filter((e) => { return ObjectHelper.objectToStringDeep(e) .indexOf(searchValue) >= 0; }); } else { return data; } } /** * Search by a Key-Value Pair in Array * @param {Array} data * @param {any} search * @return {Array} */ static searchByKeys( data: Array, search: { [Identifier: string]: string }) { if (search) { return data.filter((e) => { return this._internalFilterByKeys(e, search); }); } else { return data; } } /** * Searching Objekt for Keys. * @param {any} obj * @param {any} search * @return {boolean} */ private static _internalFilterByKeys( obj: any, search: { [Identifier: string]: string }) : boolean { return Object.keys(search).map((searchKey) => { const value = ObjectHelper.get(obj, searchKey).toString(); return value === search[searchKey]; }).reduce((sum, next) => sum && next, true); } /** * Register a Repository * @param {string} name * @param {any} clazz */ static registerRepositoryByName(name: string, clazz: any) { const _cls = BaseRepository.classes as any; _cls[name] = clazz; } /** * Getting Repository by name * @param {string} name * @return {BaseRepository} */ static getRepositoryByName( name: string): BaseRepository | undefined { const _cls = BaseRepository.classes as any; if (!_cls[name]) { return undefined; } else { const RepositoryClass = _cls[name]; return new RepositoryClass(); } } /** * @private * Replacing Values with URL-Params * @param {string} val * @return {string} */ private static _replaceParams(val: string) : string { let newSrc: string = val; const regex = /{{([a-zA-Z0-9]+)}}/; const url = new URL(window.location.href); const matches = newSrc.match(regex); if (matches) { matches.shift(); matches.forEach((m) => { newSrc = newSrc.replace('{{' + m + '}}', url.searchParams.get(m) || ''); }); } return newSrc; } private static classes : any = {}; }