| 
					
				 | 
			
			
				@@ -8,103 +8,150 @@ export default class Model { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	private _uses: number; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private _loadedRelations: string[]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	constructor(data: object) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		this._uses = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this._loadedRelations = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Object.assign(this, data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	private async _loadRelation(relation: object): Promise<object> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const { findById, registerModels } = useModelStore(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const data = await findById(relation._name, relation._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const [model] = await registerModels(data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return model; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	private async _loadRelations(model: object): Promise<object> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const relations = Object.fromEntries( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				Object.entries(model) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					.filter( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						([, value]) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							typeof value === "object" || Array.isArray(value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					.map(async ([key, value]) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						if ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							typeof value === "object" && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							value._id && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							value._name 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							return [key, await this._loadRelation(value)]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						if (Array.isArray(value)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							return [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								key, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-									value.map(async item => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-										if (typeof item !== "object") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-											return item; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-										if (item._id && item._name) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-											return this._loadRelation(item); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-										return this._loadRelations(item); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-									}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-						return [key, await this._loadRelations(value)]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private async _getRelations( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		model?: object, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		path?: string 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	): Promise<string[]> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const relationPaths = await Object.entries(model ?? this) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			.filter( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				([key, value]) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					!key.startsWith("_") && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					(typeof value === "object" || Array.isArray(value)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			.reduce(async (_modelIds, [key, value]) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				const paths = await _modelIds; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		Object.assign(model, relations); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				path = path ? `${path}.${key}` : key; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return model; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	public async loadRelations(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		await this._loadRelations(this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	private async _getRelationIds(model: object): Promise<string[]> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const relationIds = await Object.values(model) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			.filter(value => typeof value === "object" || Array.isArray(value)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			.reduce(async (_modelIds, value) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				const modelIds = await _modelIds; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				if (typeof value === "object" && value._id) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-					modelIds.push(value._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if (typeof value === "object" && value._id) paths.push(path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				else if (Array.isArray(value)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						value.map(async item => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							if (typeof item !== "object") return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-							if (item._id) modelIds.push(item._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+							if (item._id) paths.push(path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 							else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-								modelIds.push( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-									...(await this._getRelationIds(item)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+								paths.push( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+									...(await this._getRelations(item, path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 								); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 						}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 					); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				else modelIds.push(...(await this._getRelationIds(value))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				else paths.push(...(await this._getRelations(value, path))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				return modelIds; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return paths; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			}, Promise.resolve([])); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		return relationIds.filter( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			(relationId, index) => relationIds.indexOf(relationId) === index 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return relationPaths.filter( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			(relationPath, index) => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				relationPaths.indexOf(relationPath) === index 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	public async unregisterRelations(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const { unregisterModels } = useModelStore(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private async _getRelation(key: string) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		let relation = JSON.parse(JSON.stringify(this)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		key.split(".").forEach(property => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if (Number.isInteger(property)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				property = Number.parseInt(property); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			relation = relation[property]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return relation; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	private async _loadRelation( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		model: object, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		path: string, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		force: boolean, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		pathParts?: string[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		let [head, ...rest] = path.split("."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		let [next] = rest; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (Number.isInteger(head)) head = Number.parseInt(head); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (Number.isInteger(next)) next = Number.parseInt(next); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		pathParts ??= []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		const relationIds = await this._getRelationIds(this); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		pathParts.push(head); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (Array.isArray(model[head])) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				model[head].map(async (item, index) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					let itemPath = `${index}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					if (rest.length > 0) itemPath += `.${rest.join(".")}`; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					await this._loadRelation(model[head], itemPath, force, [ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+						...pathParts 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (rest.length > 0 && model[next] === null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			await this._loadRelation( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				model[head], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				rest.join("."), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				force, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				pathParts 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const fullPath = pathParts.join("."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (force || !this._loadedRelations.includes(fullPath)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			const { findById, registerModels } = useModelStore(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			const data = await findById(model[head]._name, model[head]._id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			const [registeredModel] = await registerModels(data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			model[head] = registeredModel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			this._loadedRelations.push(fullPath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (rest.length === 0) return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await model[head].loadRelations(rest.join(".")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public async loadRelations( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		relations?: string | string[], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		force = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if (relations) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			relations = Array.isArray(relations) ? relations : [relations]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			(relations ?? []).map(async path => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				await this._loadRelation(this, path, force); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	public async unregisterRelations(): Promise<void> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const { unregisterModels } = useModelStore(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		const relationIds = await Promise.all( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			this._loadedRelations.map(async path => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				const relation = await this._getRelation(path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				return relation._id; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		await unregisterModels(relationIds); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -113,7 +160,7 @@ export default class Model { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Object.assign(this, data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		await this.loadRelations(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		await this.loadRelations(this._loadedRelations, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		await this.refreshPermissions(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 |