@goatlab/fluent
Version:
Readable query Interface & API generator for TS and Node
832 lines • 33.6 kB
JavaScript
"use strict";
/**
* Inspiration: https://github.com/laravel/framework/blob/9.x/src/Illuminate/Database/Eloquent/Model.php
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeOrmConnector = void 0;
const tslib_1 = require("tslib");
const js_utils_1 = require("@goatlab/js-utils");
const bson_1 = require("bson");
const BaseConnector_1 = require("../BaseConnector");
const generatorDatasource_1 = require("../generatorDatasource");
const outputKeys_1 = require("../outputKeys");
const getMongoFindAggregatedQuery_1 = require("./queryBuilder/mongodb/getMongoFindAggregatedQuery");
const getMongoWhere_1 = require("./queryBuilder/mongodb/getMongoWhere");
const getQueryBuilderWhere_1 = require("./queryBuilder/sql/getQueryBuilderWhere");
const getTypeOrmWhere_1 = require("./queryBuilder/sql/getTypeOrmWhere");
const clearEmpties_1 = require("./util/clearEmpties");
const extractInclude_1 = require("./util/extractInclude");
const extractOrderBy_1 = require("./util/extractOrderBy");
const getRelationsFromModelGenerator_1 = require("./util/getRelationsFromModelGenerator");
class TypeOrmConnector extends BaseConnector_1.BaseConnector {
repository;
dataSourceOrGetter;
cachedDataSource = null;
get dataSource() {
if (!this.cachedDataSource) {
if (typeof this.dataSourceOrGetter === 'function') {
this.cachedDataSource = this.dataSourceOrGetter();
}
else {
this.cachedDataSource = this.dataSourceOrGetter;
}
}
return this.cachedDataSource;
}
inputSchema;
outputSchema;
entity;
constructor({ entity, dataSource, inputSchema, outputSchema, }) {
super();
this.dataSourceOrGetter = dataSource;
this.inputSchema = inputSchema;
this.outputSchema =
outputSchema || inputSchema;
this.entity = entity;
}
initDB() {
this.repository = this.dataSource.getRepository(this.entity);
this.isMongoDB =
this.repository.metadata.connection.driver.options.type === 'mongodb';
if (this.isMongoDB) {
this.repository = this.dataSource.getMongoRepository(this.entity);
}
const relationShipBuilder = generatorDatasource_1.modelGeneratorDataSource.getRepository(this.entity);
const { relations } = (0, getRelationsFromModelGenerator_1.getRelationsFromModelGenerator)(relationShipBuilder);
this.modelRelations = relations;
this.outputKeys = (0, outputKeys_1.getOutputKeys)(relationShipBuilder) || [];
return 1;
}
// CREATE
/**
* Insert the data object into the database.
* @param data
*/
async insert(data) {
this.initDB();
// Validate Input
const validatedData = this.inputSchema.parse(data);
if (this.isMongoDB && validatedData.id) {
validatedData._id = new bson_1.ObjectId(validatedData.id);
validatedData.id = undefined;
}
// Only Way to Skip the DeepPartial requirement from TypeORm
const datum = await this.repository.save(validatedData);
if (this.isMongoDB) {
datum.id = datum.id.toString();
}
// Validate Output
return this.outputSchema.parse((0, clearEmpties_1.clearEmpties)(js_utils_1.Objects.deleteNulls(datum)));
}
async insertMany(data) {
this.initDB();
const validatedData = this.inputSchema.array().parse(data);
//
const inserted = await this.repository.save(validatedData, {
chunk: data.length / 300,
});
const processedData = new Array(inserted.length);
for (let i = 0; i < inserted.length; i++) {
const d = inserted[i];
if (this.isMongoDB) {
// Handle both _id and id cases
if (d._id) {
d.id = d._id.toString();
delete d._id;
}
else if (d.id && typeof d.id !== 'string') {
d.id = d.id.toString();
}
}
processedData[i] = (0, clearEmpties_1.clearEmpties)(js_utils_1.Objects.deleteNulls(d));
}
return this.outputSchema.array().parse(processedData);
}
// READ
async findMany(query) {
this.initDB();
const requiresCustomQuery = query?.include && Object.keys(query.include).length;
if (this.isMongoDB && requiresCustomQuery) {
const results = await this.customMongoRelatedFind(query);
return results;
}
if (requiresCustomQuery) {
const { queryBuilder: customQuery, selectedKeys } = this.customTypeOrmRelatedFind({
fluentQuery: query,
});
customQuery.select(selectedKeys);
// Get the count for pagination
// TODO: do the pagination
const [result, _count] = await customQuery.getManyAndCount();
// Process MongoDB IDs if needed
for (let i = 0; i < result.length; i++) {
const d = result[i];
if (this.isMongoDB) {
// Handle both _id and id cases
if (d._id) {
d.id = d._id.toString();
delete d._id;
}
else if (d.id && typeof d.id !== 'string') {
d.id = d.id.toString();
}
}
(0, clearEmpties_1.clearEmpties)(js_utils_1.Objects.deleteNulls(d));
}
// Apply select filtering if needed
// Validate the results
const validatedResult = this.outputSchema
?.array()
.parse(result);
return validatedResult;
}
// Generate normal TypeORM Query
const generatedQuery = this.generateTypeOrmQuery(query);
const [found, count] = await this.repository.findAndCount(generatedQuery);
for (let i = 0; i < found.length; i++) {
const d = found[i];
if (this.isMongoDB) {
// Handle both _id and id cases
if (d._id) {
d.id = d._id.toString();
delete d._id;
}
else if (d.id && typeof d.id !== 'string') {
d.id = d.id.toString();
}
}
(0, clearEmpties_1.clearEmpties)(js_utils_1.Objects.deleteNulls(d));
}
// Apply select filter if needed
let processedResults = found;
if (query?.select) {
// Filter out fields that are explicitly set to false
processedResults = this.applySelectFilter(found, query.select);
}
// Validate the results - skip validation if select is used (partial objects)
const validatedFound = query?.select
? processedResults
: this.outputSchema
?.array()
.parse(processedResults);
if (query?.paginated) {
const paginationInfo = {
total: count,
perPage: query.paginated.perPage,
currentPage: query.paginated.page,
nextPage: query.paginated.page + 1,
firstPage: 1,
lastPage: Math.ceil(count / query.paginated.perPage),
prevPage: query.paginated.page === 1 ? null : query.paginated.page - 1,
from: (query.paginated.page - 1) * query.paginated.perPage + 1,
to: query.paginated.perPage * query.paginated.page,
data: validatedFound,
};
return paginationInfo;
}
// Return the already validated results
return validatedFound;
}
// UPDATE
/**
* PATCH operation
* @param data
*/
async updateById(id, data) {
this.initDB();
const dataToInsert = this.outputKeys.includes('updated')
? {
...data,
...{ updated: new Date() },
}
: data;
const validatedData = this.inputSchema.parse(dataToInsert);
await this.repository.update(id, validatedData);
// Validate Output
return (await this.requireById(id));
}
/**
*
* PUT operation. All fields not included in the data
* param will be set to null
*
* @param id
* @param data
*/
async replaceById(id, data) {
this.initDB();
const _idFieldName = this.isMongoDB ? '_id' : 'id';
const value = this.requireById(id);
const flatValue = js_utils_1.Objects.flatten(JSON.parse(JSON.stringify(value)));
Object.keys(flatValue).forEach(key => {
;
flatValue[key] = null;
});
const nullObject = js_utils_1.Objects.nest(flatValue);
const newValue = { ...nullObject, ...data };
newValue._id = undefined;
newValue.id = undefined;
newValue.created = undefined;
newValue.updated = undefined;
const dataToInsert = this.outputKeys.includes('updated')
? {
...data,
...{ updated: new Date() },
}
: data;
const validatedData = this.inputSchema.parse(dataToInsert);
await this.repository.update(id, validatedData);
return (await this.requireById(id));
}
// DELETE
/**
*
* @param id
* @returns
*/
async deleteById(id) {
this.initDB();
const parsedId = this.isMongoDB ? new bson_1.ObjectId(id) : id;
await this.repository.delete(parsedId);
return id;
}
/**
*
* @returns
*/
async clear() {
this.initDB();
await this.repository.clear();
return true;
}
// RELATIONS
/**
*
* @param query
* @returns
*/
loadFirst(query) {
this.initDB();
// Create a clone of the original class
// to avoid polluting attributes (relatedQuery)
const newInstance = this.clone();
newInstance.setRelatedQuery({
entity: this.entity,
repository: this,
query: {
...query,
limit: 1,
},
});
return newInstance;
}
/**
*
* @param id
* @returns
*/
loadById(id) {
this.initDB();
// Create a new instance to avoid polluting the original one
const newInstance = this.clone();
newInstance.setRelatedQuery({
entity: this.entity,
repository: this,
query: {
where: {
id,
},
},
});
return newInstance;
}
/**
*
* Returns the TypeOrm Repository, you can use it
* form more complex queries and to get
* the TypeOrm query builder
*
* @param query
*/
raw() {
this.initDB();
return this.repository;
}
/**
*
* Returns the TypeOrm Repository, you can use it
* form more complex queries and to get
* the TypeOrm query builder
*
* @param query
*/
mongoRaw() {
this.initDB();
return this.repository;
}
/**
* Creates a Clone of the current instance of the class
* @returns
*/
clone() {
this.initDB();
return new this.constructor();
}
/**
* Apply select filter to remove fields explicitly set to false
* @param results The query results
* @param select The select configuration
* @returns Filtered results
*/
applySelectFilter(results, select) {
if (!select) {
return results;
}
const flatSelect = js_utils_1.Objects.flatten(select);
const fieldsToInclude = new Set();
const fieldsToExclude = new Set();
let hasIncludes = false;
// Separate fields to include and exclude
for (const [key, value] of Object.entries(flatSelect)) {
// Convert to string for consistent comparison
const strValue = String(value);
if (strValue === 'true' || strValue === '1') {
fieldsToInclude.add(key);
hasIncludes = true;
}
else if (strValue === 'false' || strValue === '0') {
fieldsToExclude.add(key);
}
}
return results.map(result => {
if (hasIncludes) {
return this.applyInclusiveSelection(result, fieldsToInclude);
}
return this.applyExclusiveSelection(result, fieldsToExclude);
});
}
applyInclusiveSelection(result, fieldsToInclude) {
const filtered = {};
for (const field of fieldsToInclude) {
if (field.includes('.')) {
this.copyNestedField(result, filtered, field);
}
else if (field in result) {
filtered[field] = result[field];
}
}
return filtered;
}
applyExclusiveSelection(result, fieldsToExclude) {
const filtered = { ...result };
for (const field of fieldsToExclude) {
if (field.includes('.')) {
this.deleteNestedField(filtered, field);
}
else {
delete filtered[field];
}
}
return filtered;
}
copyNestedField(source, target, fieldPath) {
const parts = fieldPath.split('.');
let currentSource = source;
let currentTarget = target;
for (let i = 0; i < parts.length - 1; i++) {
const part = parts[i];
if (!part || !currentSource[part]) {
return;
}
currentSource = currentSource[part];
if (!currentTarget[part]) {
currentTarget[part] = {};
}
currentTarget = currentTarget[part];
}
if (currentSource && parts.length > 0) {
const lastPart = parts[parts.length - 1];
if (lastPart) {
currentTarget[lastPart] = currentSource[lastPart];
}
}
}
deleteNestedField(target, fieldPath) {
const parts = fieldPath.split('.');
let current = target;
for (let i = 0; i < parts.length - 1; i++) {
const part = parts[i];
if (!part || !current[part]) {
return;
}
current = current[part];
}
if (current && parts.length > 0) {
const lastPart = parts[parts.length - 1];
if (lastPart) {
delete current[lastPart];
}
}
}
/**
*
* @param query
* @returns
*/
generateTypeOrmQuery(query) {
const filter = {};
filter.where = this.isMongoDB
? (0, getMongoWhere_1.getMongoWhere)({
where: query?.where,
})
: (0, getTypeOrmWhere_1.getTypeOrmWhere)({
where: query?.where,
});
filter.take = query?.limit;
filter.skip = query?.offset;
// Pagination
if (query?.paginated) {
filter.take = query.paginated.perPage;
filter.skip = (query.paginated?.page - 1) * query?.paginated.perPage;
}
if (query?.select) {
const selectQuery = js_utils_1.Objects.flatten(query?.select || {});
// Filter out fields with false values - TypeORM only accepts fields to include
const fieldsToSelect = Object.keys(selectQuery).filter(key => {
const val = selectQuery[key];
return (val !== undefined && (String(val) === 'true' || String(val) === '1'));
});
if (fieldsToSelect.length > 0) {
// TypeORM expects select to be an object with field names as keys
const selectObject = fieldsToSelect.reduce((acc, field) => {
acc[field] = true;
return acc;
}, {});
filter.select = selectObject;
}
}
if (query?.orderBy) {
filter.order = (0, extractOrderBy_1.extractOrderBy)(query.orderBy);
}
if (query?.include) {
filter.relations = (0, extractInclude_1.extractInclude)(query.include);
}
return filter;
}
/**
*
* @param query
* @returns
*/
customTypeOrmRelatedFind({ fluentQuery: query, queryBuilder, targetFluentRepository, alias, isLeftJoin, }) {
const queryAlias = alias || queryBuilder?.alias || `${this.repository.metadata.tableName}`;
let customQuery = queryBuilder || this.raw().createQueryBuilder(queryAlias);
const self = targetFluentRepository || this;
if (!isLeftJoin) {
customQuery = (0, getQueryBuilderWhere_1.getQueryBuilderWhere)({
queryBuilder: customQuery,
queryAlias,
where: query?.where,
});
}
const { queryBuilder: qb, selectedKeys } = this.getTypeOrmQueryBuilderSubqueries({
queryBuilder: customQuery,
selfReference: targetFluentRepository,
include: query?.include,
leftTableAlias: alias,
});
customQuery = qb;
const extraKeys = this.getTypeOrmQueryBuilderSelect(queryAlias, self, query?.select);
const keySet = new Set([...selectedKeys, ...extraKeys]);
// if (query?.limit) {
// customQuery = customQuery.limit(query?.limit)
// }
// if (query?.offset) {
// customQuery = customQuery.offset(query?.offset)
// }
// if (query?.take) {
// customQuery = customQuery.take(query?.take)
// }
return {
queryBuilder: customQuery,
selectedKeys: Array.from(keySet),
};
}
getTypeOrmQueryBuilderSelect(queryAlias, self, select) {
const selected = js_utils_1.Objects.flatten(select || {});
const selectedKeys = [];
const iterableKeys = Object.keys(selected).length
? Object.keys(selected)
: self.outputKeys || [];
const baseNestedKeys = new Set();
for (const key of iterableKeys) {
const keyArray = key.split('.');
// There are no nested objects
if (keyArray.length <= 1) {
continue;
}
const total = keyArray.length;
for (const [index, val] of keyArray.entries()) {
// No need to iterate over the last object
if (total === index + 1) {
continue;
}
let excludedField = '';
if (excludedField) {
excludedField = `${excludedField}.${excludedField}${val}`;
}
excludedField = `${excludedField}${val}`;
baseNestedKeys.add(excludedField);
}
}
for (const k of iterableKeys) {
const field = k.includes('.') ? js_utils_1.Strings.camel(`${k}`) : k;
const search = `${queryAlias}.${field}`;
// isRelatedField: We can tell if the field is a "related model"
// checking "this" for the name of the relation
let isNestedRelation = false;
for (const item of k.split('.')) {
if (self[item]) {
isNestedRelation = true;
break;
}
}
if (!!self[field] || !!self[queryAlias] || isNestedRelation) {
continue;
}
// No need to include base keys
if (baseNestedKeys.has(field)) {
continue;
}
selectedKeys.push(search);
}
return selectedKeys;
}
getTypeOrmQueryBuilderSubqueries({ queryBuilder, selfReference, include, leftTableAlias, }) {
const selectedKeys = [];
if (!include) {
return { queryBuilder, selectedKeys };
}
for (const relation of Object.keys(include)) {
// i.e To make this code more understandable
// table "users" has many "cars"
// For a first level query, represents "users"
const self = selfReference || this;
// All information about the users[cars] relation
const dbRelation = self.modelRelations[relation];
// The "cars" table repository
// this will be use for possible recursive queries
const newSelf = self[relation]();
// Extract new query for this included relationship
const fluentRelatedQuery = include[relation] === true ? {} : include[relation];
if (!dbRelation) {
throw new Error(`The relation ${relation} is not properly defined. Check your entity and repository`);
}
// Now we need to decide which properties we want to select from the related model
// If the query has some {select: [x]: true}
const selectedKeysArray = fluentRelatedQuery?.select
? Object.keys(js_utils_1.Objects.flatten(fluentRelatedQuery.select))
: [];
if (dbRelation.isManyToOne) {
// We now have the opposite "cars" has one "users"
// "cars"
// Or users___cars if it comes from a nested relation
const leftSideTableName = leftTableAlias || queryBuilder.alias;
// "cars.userId"
// users___cars.userId (if nested)
const leftSideForeignKey = `${leftSideTableName}.${dbRelation.joinColumns[0].propertyPath}`;
// Right side considering nested relations
// users___cars___cars___user
const rightSideTableName = `${leftSideTableName}_${relation}`;
const rightSidePrimaryKey = `${rightSideTableName}.id`;
const keys = new Set(selectedKeysArray.map(k => `${rightSideTableName}.${k}`));
selectedKeys.push(...Array.from(keys));
const shallowQuery = { ...fluentRelatedQuery };
shallowQuery.include = undefined;
const { queryBuilder: leftJoinBuilder, selectedKeys: deepkeys } = this.customTypeOrmRelatedFind({
queryBuilder: this.raw().createQueryBuilder(rightSideTableName),
fluentQuery: shallowQuery,
targetFluentRepository: newSelf,
alias: rightSideTableName,
});
selectedKeys.push(...deepkeys);
const joinQuery = leftJoinBuilder.getQuery().split('WHERE');
const customLeftJoin = joinQuery?.[1] ? joinQuery[1].trim() : '1=1';
const leftJoinParams = leftJoinBuilder.getParameters();
// Finally we get to do the LEFT JOIN
queryBuilder.leftJoinAndMapOne(`${leftSideTableName}.${relation}`, dbRelation.targetClass,
// Right side of the JOIN table name
// The name of the table that comes from the query above!
rightSideTableName,
// Keys to JOIN ON
// This must account for all aliases used above
`(${leftSideForeignKey} = ${rightSidePrimaryKey} AND ${customLeftJoin} )`, leftJoinParams);
const { queryBuilder: qb, selectedKeys: k } = this.customTypeOrmRelatedFind({
queryBuilder,
fluentQuery: fluentRelatedQuery,
targetFluentRepository: newSelf,
alias: rightSideTableName,
isLeftJoin: true,
});
selectedKeys.push(...k);
queryBuilder = qb;
}
if (dbRelation.isOneToMany) {
// "users"
const leftSideTableName = leftTableAlias || queryBuilder.alias;
// As it is one to many, primary key will always be "id"
// users.id
const leftSidePrimaryKey = `${leftSideTableName}.id`;
// "cars"
const rightSideTableName = `${leftSideTableName}_${relation}`;
// "cars".userId
const rightSideForeignKey = `${rightSideTableName}.${dbRelation.inverseSidePropertyPath}`;
const keys = new Set(selectedKeysArray.map(k => `${rightSideTableName}.${k}`));
selectedKeys.push(...Array.from(keys));
// Left join query, without including any nested tables
const shallowQuery = { ...fluentRelatedQuery };
shallowQuery.include = undefined;
const { queryBuilder: leftJoinBuilder, selectedKeys: deepKeys } = this.customTypeOrmRelatedFind({
queryBuilder: this.raw().createQueryBuilder(rightSideTableName),
fluentQuery: shallowQuery,
targetFluentRepository: newSelf,
alias: rightSideTableName,
});
selectedKeys.push(...deepKeys);
const joinQuery = leftJoinBuilder.getQuery().split('WHERE');
const customLeftJoin = joinQuery?.[1] ? joinQuery[1].trim() : '1=1';
const leftJoinParams = leftJoinBuilder.getParameters();
// Finally we get to do the LEFT JOIN
queryBuilder.leftJoinAndMapMany(`${leftSideTableName}.${relation}`, dbRelation.targetClass,
// Right side of the JOIN table name
rightSideTableName,
// Keys to JOIN ON
`(${leftSidePrimaryKey} = ${rightSideForeignKey} AND ${customLeftJoin} )`, leftJoinParams);
const { queryBuilder: q, selectedKeys: k } = this.customTypeOrmRelatedFind({
queryBuilder,
fluentQuery: fluentRelatedQuery,
targetFluentRepository: newSelf,
alias: rightSideTableName,
isLeftJoin: true,
});
selectedKeys.push(...k);
queryBuilder = q;
}
// if (dbRelation.isManyToMany) {
// const relatedTableName = dbRelation.tableName
// const pivotTableName =
// dbRelation.joinColumns[0].relationMetadata.joinTableName
// const pivotForeignField = dbRelation.joinColumns[0].propertyPath
// const inverseForeignField =
// dbRelation.inverseJoinColumns[0].propertyPath
// if (
// !relatedTableName ||
// !pivotTableName ||
// !pivotForeignField ||
// !inverseForeignField
// ) {
// throw new Error(
// `Your many to many relation is not properly set up. Please check both your models and schema for relation: ${relation}`
// )
// }
// // "users"
// const leftSideTableName = leftTableAlias || queryBuilder.alias
// // As it is one to many, primary key will always be "id"
// // users.id
// const leftSidePrimaryKey = `${leftSideTableName}.id`
// // "roles_users"
// const rightSideTableName = `${relatedTableName}`
// // "roles_users".userId
// const rightSideForeignKey = `${rightSideTableName}.${pivotForeignField}`
// const keys = new Set(
// selectedKeysArray.map(k => `${rightSideTableName}.${k}`)
// )
// selectedKeys.push(...Array.from(keys))
// // Left join query, without including any nested tables
// const shallowQuery = { ...fluentRelatedQuery }
// delete shallowQuery['include']
// const { queryBuilder: leftJoinBuilder, selectedKeys: deepKeys } =
// this.customTypeOrmRelatedFind({
// queryBuilder: this.raw().createQueryBuilder(rightSideTableName),
// fluentQuery: shallowQuery,
// targetFluentRepository: newSelf,
// alias: rightSideTableName
// })
// selectedKeys.push(...deepKeys)
// const joinQuery = leftJoinBuilder.getQuery().split('WHERE')
// const customLeftJoin =
// joinQuery && joinQuery[1] ? joinQuery[1].trim() : '1=1'
// const leftJoinParams = leftJoinBuilder.getParameters()
// // Finally we get to do the LEFT JOIN
// queryBuilder.leftJoinAndMapMany(
// `${leftSideTableName}.${relation}`,
// dbRelation.targetClass,
// // Right side of the JOIN table name
// rightSideTableName,
// // Keys to JOIN ON
// `(${leftSidePrimaryKey} = ${rightSideForeignKey} AND ${customLeftJoin} )`,
// leftJoinParams
// )
// const { queryBuilder: q, selectedKeys: k } =
// this.customTypeOrmRelatedFind({
// queryBuilder,
// fluentQuery: fluentRelatedQuery,
// targetFluentRepository: newSelf,
// alias: rightSideTableName,
// isLeftJoin: true
// })
// selectedKeys.push(...k)
// queryBuilder = q
// console.log(
// relatedTableName,
// pivotTableName,
// pivotForeignField,
// inverseForeignField
// )
// continue
// // lookUps.push({ $addFields: { id: { $toString: '$_id' } } })
// // lookUps.push({
// // $addFields: { parentStringId: { $toString: '$_id' } }
// // })
// // lookUps.push({
// // $lookup: {
// // from: pivotTableName,
// // localField: 'parentStringId',
// // foreignField: pivotForeignField,
// // as: dbRelation.propertyName,
// // pipeline: [
// // // This is the pivot table
// // { $addFields: { id: { $toString: '$_id' } } },
// // {
// // $addFields: {
// // [`${inverseForeignField}_object`]: {
// // $toObjectId: `$${inverseForeignField}`
// // }
// // }
// // },
// // // The other side of the relationShip
// // {
// // $lookup: {
// // from: relatedTableName,
// // localField: `${inverseForeignField}_object`,
// // foreignField: '_id',
// // pipeline: [
// // { $addFields: { id: { $toString: '$_id' } } }
// // // Here we could add more filters like
// // //{ $limit: 2 }
// // ],
// // as: dbRelation.propertyName
// // }
// // },
// // { $unwind: `$${dbRelation.propertyName}` },
// // // Select (ish)
// // {
// // $project: {
// // [dbRelation.propertyName]: `$${dbRelation.propertyName}`,
// // pivot: '$$ROOT'
// // }
// // },
// // {
// // $replaceRoot: {
// // newRoot: {
// // $mergeObjects: ['$$ROOT', `$${dbRelation.propertyName}`]
// // }
// // }
// // },
// // { $project: { [dbRelation.propertyName]: 0 } }
// // // Here we could add more filters like
// // //{ $limit: 2 }
// // ]
// // }
// // })
// }
}
return { queryBuilder, selectedKeys };
}
/**
*
* @param query
* @returns
*/
async customMongoRelatedFind(query) {
const aggregate = (0, getMongoFindAggregatedQuery_1.getMongoFindAggregatedQuery)({
query,
self: this,
});
const raw = await this.mongoRaw().aggregate(aggregate).toArray();
if (query?.select) {
// Apply select filtering for MongoDB results
const filtered = this.applySelectFilter(raw, query.select);
return filtered;
}
return this.outputSchema?.array().parse(raw);
}
}
exports.TypeOrmConnector = TypeOrmConnector;
tslib_1.__decorate([
js_utils_1.Memo.syncMethod(),
tslib_1.__metadata("design:type", Function),
tslib_1.__metadata("design:paramtypes", []),
tslib_1.__metadata("design:returntype", void 0)
], TypeOrmConnector.prototype, "initDB", null);
//# sourceMappingURL=TypeOrmConnector.js.map