@goatlab/fluent
Version:
Readable query Interface & API generator for TS and Node
258 lines (257 loc) • 9.32 kB
JavaScript
"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;