UNPKG

@goatlab/fluent

Version:

Readable query Interface & API generator for TS and Node

258 lines (257 loc) 9.32 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseConnector = void 0; const js_utils_1 = require("@goatlab/js-utils"); const clearEmpties_1 = require("./TypeOrmConnector/util/clearEmpties"); class BaseConnector { constructor() { this.chunk = null; this.pullSize = null; this.paginator = undefined; this.rawQuery = undefined; this.chunk = null; this.pullSize = null; this.paginator = undefined; this.rawQuery = undefined; this.outputKeys = []; } async insertMany(data) { throw new Error('get() method not implemented'); } async updateById(id, data) { throw new Error('get() method not implemented'); } async findMany(query) { throw new Error('findMany() method not implemented'); } async findFirst(query) { const data = await this.findMany({ ...query, limit: 1 }); if (!data[0]) { return null; } return data[0]; } async requireById(id, q) { const found = await this.findByIds([id], { select: q?.select, include: q?.include, limit: 1 }); found.map(d => { if (this.isMongoDB) { d['id'] = d['id'].toString(); } (0, clearEmpties_1.clearEmpties)(js_utils_1.Objects.deleteNulls(d)); }); if (!found[0]) { throw new Error(`Object ${id} not found`); } return found[0]; } async requireFirst(query) { const found = await this.findMany({ ...query, limit: 1 }); found.map(d => { if (this.isMongoDB) { d['id'] = d['id'].toString(); } (0, clearEmpties_1.clearEmpties)(js_utils_1.Objects.deleteNulls(d)); }); if (!found[0]) { const stringQuery = query ? JSON.stringify(query) : ''; throw new Error(`No objects found matching: ${stringQuery}`); } return found[0]; } async findByIds(ids, q) { let data = await this.findMany({ where: { id: { in: ids } }, limit: q?.limit, select: q?.select, include: q?.include }); return data; } async findById(id, q) { const result = await this.findByIds([id], { ...q, limit: 1 }); if (!result[0]) { return null; } return result[0]; } async collect(query) { const data = await this.findMany(query); if (!Array.isArray(data)) { return new js_utils_1.Collection([data]); } return new js_utils_1.Collection(data); } async pluck(path, query) { const data = await this.findMany(query); const paths = Object.keys(js_utils_1.Objects.flatten(path)); const result = data.map(e => { const extracted = js_utils_1.Objects.getFromPath(e, String(paths[0]), undefined); if (typeof extracted.value !== 'undefined') { return extracted.value; } }); return result; } setRelatedQuery(r) { this.relatedQuery = r; } async associate(data) { if (!this.relatedQuery?.entity || !this.relatedQuery.key) { throw new Error('Associate can only be called as a related model'); } const parentData = await this.relatedQuery.repository.findMany({ ...this.relatedQuery.query, select: { id: true } }); let foreignKeyName = this.relatedQuery['repository']['modelRelations'][this.relatedQuery.key] .inverseSidePropertyPath; if (!foreignKeyName) { throw new Error('The relationship was not properly defined. Please check that your Repository and Model relations have the same keys'); } const relatedData = parentData.map(r => ({ [foreignKeyName]: r.id, ...data })); const existingIds = (0, clearEmpties_1.clearEmpties)(relatedData.map(r => r.id)); const existingData = existingIds.length ? await this.findByIds(relatedData.map(r => r.id)) : []; const updateQueries = []; const insertQueries = []; for (const related of relatedData) { const exists = existingData.find((d) => { const p = d; return p.id === related.id; }); if (exists) { updateQueries.push(this.updateById(exists.id, { ...exists, [foreignKeyName]: related[foreignKeyName] })); } else { insertQueries.push(related); } } const updateResult = await Promise.all(updateQueries); const insertedResult = await this.insertMany(insertQueries); return [...updateResult, ...insertedResult]; } async attach(id, pivot) { if (!this.relatedQuery?.entity || !this.relatedQuery.key) { throw new Error('Associate can only be called as a related model'); } const parentData = await this.relatedQuery.repository.findMany({ ...this.relatedQuery.query, select: { id: true } }); const foreignKeyName = this.relatedQuery['repository']['modelRelations'][this.relatedQuery.key] .joinColumns[0].propertyPath; const inverseKeyName = this.relatedQuery['repository']['modelRelations'][this.relatedQuery.key] .inverseJoinColumns[0].propertyPath; if (!foreignKeyName || !inverseKeyName) { throw new Error(`The relationship was not properly defined. Please check that your Repository and Model relations have the same keys: Searching for: ${this.relatedQuery.key}`); } const relatedData = parentData.map(d => ({ [foreignKeyName]: d.id, [inverseKeyName]: id, ...pivot })); return this.relatedQuery.pivot.insertMany(relatedData); } hasMany(r) { const newRepo = new r.repository(); const calleeName = new Error('dummy') .stack.split('\n')[2] .replace(/^\s+at\s+(.+?)\s.+/g, '$1') .split('.')[1]; if (this.relatedQuery) { newRepo.setRelatedQuery({ ...this.relatedQuery, key: calleeName }); } return newRepo; } belongsTo(r) { return this.hasMany(r); } hasOne() { throw new Error('Method not implemented'); } belongsToMany(r) { const newRepo = new r.repository(); const relationName = new Error('dummy') .stack.split('\n')[2] .replace(/^\s+at\s+(.+?)\s.+/g, '$1') .split('.')[1]; const pivot = new r.pivot(); pivot.setRelatedQuery({ ...this.relatedQuery, key: relationName }); if (this.relatedQuery) { newRepo.setRelatedQuery({ ...this.relatedQuery, key: relationName, pivot }); } else { newRepo.setRelatedQuery({ key: relationName, pivot }); } return newRepo; } hasManyThrough() { throw new Error('Method not implemented'); } jsApplySelect(select, data) { const _data = Array.isArray(data) ? [...data] : [data]; if (!select) { return data; } const selectedAttributes = Object.keys(js_utils_1.Objects.flatten(select)); const iterationArray = this.outputKeys.length === 0 && selectedAttributes.length > 0 ? selectedAttributes : [...this.outputKeys]; const compareArray = this.outputKeys.length === 0 && selectedAttributes.length > 0 ? [...this.outputKeys] : selectedAttributes; return _data.map(element => { const newElement = {}; iterationArray.forEach(attribute => { if (compareArray.length > 0 && !compareArray.includes(attribute)) { return undefined; } const extract = js_utils_1.Objects.getFromPath(element, attribute, undefined); let value = js_utils_1.Objects.get(() => extract.value, undefined); if (typeof value !== 'undefined' && value !== null) { if (typeof value === 'object' && value.hasOwnProperty('data') && value.data.hasOwnProperty('name')) { newElement[extract.label] = value.data.name; } else { if (typeof value === 'object' && js_utils_1.Ids.isValidObjectID(value)) { value = js_utils_1.Ids.objectIdString(value); } newElement[extract.label] = value; } } }); return js_utils_1.Objects.nest(newElement); }); } } exports.BaseConnector = BaseConnector;