| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const { cloneDeep } = require('lodash/fp'); | 
					
						
							|  |  |  | const { createAsyncSeriesHook, createAsyncParallelHook } = require('./hooks'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef ProviderHooksMap | 
					
						
							|  |  |  |  * @property willRegister | 
					
						
							|  |  |  |  * @property didRegister | 
					
						
							|  |  |  |  * @property willDelete | 
					
						
							|  |  |  |  * @property didDelete | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Creates a new object containing various hooks used by the providers | 
					
						
							|  |  |  |  * @return {ProviderHooksMap} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const createProviderHooksMap = () => ({ | 
					
						
							|  |  |  |   // Register events
 | 
					
						
							|  |  |  |   willRegister: createAsyncSeriesHook(), | 
					
						
							|  |  |  |   didRegister: createAsyncParallelHook(), | 
					
						
							|  |  |  |   // Delete events
 | 
					
						
							|  |  |  |   willDelete: createAsyncParallelHook(), | 
					
						
							|  |  |  |   didDelete: createAsyncParallelHook(), | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							| 
									
										
										
										
											2022-07-21 10:43:19 +02:00
										 |  |  |  * A Provider factory | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  |  * @param {Object} [options] - The factory options | 
					
						
							|  |  |  |  * @param {boolean = true} options.throwOnDuplicates - Specify the wanted behaviour when encountering a duplicate key on register | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | const providerFactory = (options = {}) => { | 
					
						
							|  |  |  |   const { throwOnDuplicates = true } = options; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const state = { | 
					
						
							|  |  |  |     hooks: createProviderHooksMap(), | 
					
						
							|  |  |  |     registry: new Map(), | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     hooks: state.hooks, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async register(key, item) { | 
					
						
							|  |  |  |       if (throwOnDuplicates && this.has(key)) { | 
					
						
							|  |  |  |         throw new Error(`Duplicated item key: ${key}`); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       await state.hooks.willRegister.call({ key, value: item }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       state.registry.set(key, item); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       await state.hooks.didRegister.call({ key, value: cloneDeep(item) }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return this; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async delete(key) { | 
					
						
							|  |  |  |       if (this.has(key)) { | 
					
						
							|  |  |  |         const item = this.get(key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await state.hooks.willDelete.call({ key, value: cloneDeep(item) }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         state.registry.delete(key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await state.hooks.didDelete.call({ key, value: cloneDeep(item) }); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return this; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     get(key) { | 
					
						
							|  |  |  |       return state.registry.get(key); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     getWhere(filters = {}) { | 
					
						
							|  |  |  |       const items = this.values(); | 
					
						
							|  |  |  |       const filtersEntries = Object.entries(filters); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (filtersEntries.length === 0) { | 
					
						
							|  |  |  |         return items; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-08 23:33:39 +02:00
										 |  |  |       return items.filter((item) => { | 
					
						
							| 
									
										
										
										
											2021-03-25 14:59:44 +01:00
										 |  |  |         return filtersEntries.every(([key, value]) => item[key] === value); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     values() { | 
					
						
							|  |  |  |       return Array.from(state.registry.values()); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     keys() { | 
					
						
							|  |  |  |       return Array.from(state.registry.keys()); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     has(key) { | 
					
						
							|  |  |  |       return state.registry.has(key); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     size() { | 
					
						
							|  |  |  |       return state.registry.size; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async clear() { | 
					
						
							|  |  |  |       const keys = this.keys(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       for (const key of keys) { | 
					
						
							|  |  |  |         await this.delete(key); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return this; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = providerFactory; |