Skip to content

Commit

Permalink
feat(mongodb): Add support for find relations with MongoDB
Browse files Browse the repository at this point in the history
  • Loading branch information
marian2js authored and doug-martin committed Oct 16, 2020
1 parent ce4c5e9 commit f4190e6
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 56 deletions.
4 changes: 2 additions & 2 deletions packages/query-typeorm-mongo/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { TypeOrmQueryService, TypeOrmQueryServiceOpts } from './services';
export { NestjsQueryTypeOrmModule } from './module';
export { TypeOrmMongoQueryService, TypeOrmMongoQueryServiceOpts } from './services';
export { NestjsQueryTypeOrmMongoModule } from './module';
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
DeepPartial,
DeleteManyResponse,
Filter,
FilterComparisons,
Query,
QueryService,
UpdateManyResponse,
Expand All @@ -17,6 +16,17 @@ export interface TypeOrmMongoQueryServiceOpts<Entity> {
useSoftDelete?: boolean;
}

const mongoOperatorMapper: { [k: string]: string } = {
eq: '$eq',
neq: '$ne',
gt: '$gt',
gte: '$gte',
lt: '$lt',
lte: '$lte',
in: '$in',
notIn: '$nin',
};

/**
* Base class for all query services that use a `typeorm` Repository.
*
Expand Down Expand Up @@ -48,35 +58,34 @@ export class TypeOrmMongoQueryService<Entity> implements QueryService<Entity> {
}

protected buildExpression(filter: Filter<Entity>): FindConditions<Entity> {
const where: FindConditions<Entity> = {};

Object.entries(filter).forEach(([key, value]) => {
return Object.entries(filter).reduce((prev: FindConditions<Entity>, [key, value]) => {
if (!value) {
return prev;
}
if (Array.isArray(value)) {
where[`$${key}`] = value.map((subFilter) => this.buildExpression(subFilter));
} else if (value) {
Object.entries(value).forEach(([fieldKey, fieldValue]) => {
let mongoOperator: string | undefined;
if (['eq', 'gt', 'gte', 'lt', 'lte', 'in'].includes(fieldKey)) {
mongoOperator = `$${fieldKey}`;
}
if (fieldKey === 'neq') {
mongoOperator = '$ne';
}
if (fieldKey === 'notIn') {
mongoOperator = '$nin';
}
if (mongoOperator) {
where[key] = {
[mongoOperator]: fieldValue,
return {
...prev,
[`$${key}`]: value.map((subFilter) => this.buildExpression(subFilter)),
};
}
const findConditions = Object.entries(value).reduce(
(prevCondition: FindConditions<Entity>, [fieldKey, fieldValue]) => {
if (mongoOperatorMapper[fieldKey]) {
return {
...prevCondition,
[mongoOperatorMapper[fieldKey]]: fieldValue,
};
} else {
this.logger.error(`Operator ${fieldKey} not supported yet`);
}
});
}
});

return where;
this.logger.error(`Operator ${fieldKey} not supported yet`);
return prevCondition;
},
{},
);
return {
...prev,
[key]: findConditions,
};
}, {});
}

/**
Expand Down Expand Up @@ -314,75 +323,111 @@ export class TypeOrmMongoQueryService<Entity> implements QueryService<Entity> {
}
}

queryRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dto: Entity,
query: Query<Relation>,
): Promise<Relation[]>;
queryRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dtos: Entity[],
query: Query<Relation>,
): Promise<Map<Entity, Relation[]>>;
queryRelations(RelationClass: any, relationName: any, dtos: any, query: any) {
/**
* Adds multiple relations.
* @param relationName - The name of the relation to query for.
* @param id - The id of the dto to add the relation to.
* @param relationIds - The ids of the relations to add.
*/
addRelations<Relation>(relationName: string, id: string | number, relationIds: (string | number)[]): Promise<Entity> {
throw new Error('Not implemented yet');
}

aggregateRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
entities: Entity[],
filter: Filter<Relation>,
aggregate: AggregateQuery<Relation>,
): Promise<Map<Entity, AggregateResponse<Relation>>>;

aggregateRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dto: Entity,
filter: Filter<Relation>,
aggregate: AggregateQuery<Relation>,
): Promise<AggregateResponse<Relation>>;

aggregateRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dtos: Entity[],
dto: Entity | Entity[],
filter: Filter<Relation>,
aggregate: AggregateQuery<Relation>,
): Promise<Map<Entity, AggregateResponse<Relation>>>;
aggregateRelations(RelationClass: any, relationName: any, dtos: any, filter: any, aggregate: any) {
): Promise<AggregateResponse<Relation> | Map<Entity, AggregateResponse<Relation>>> {
throw new Error('Not implemented yet');
}

countRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
entities: Entity[],
filter: Filter<Relation>,
): Promise<Map<Entity, number>>;

countRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dto: Entity,
filter: Filter<Relation>,
): Promise<number>;

countRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dto: Entity[],
dto: Entity | Entity[],
filter: Filter<Relation>,
): Promise<Map<Entity, number>>;
countRelations(RelationClass: any, relationName: any, dto: any, filter: any) {
): Promise<number | Map<Entity, number>> {
throw new Error('Not implemented yet');
}

findRelation<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dtos: Entity[],
): Promise<Map<Entity, Relation | undefined>>;
findRelation<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dto: Entity,
): Promise<Relation | undefined>;
findRelation<Relation>(
async findRelation<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dtos: Entity[],
): Promise<Map<Entity, Relation | undefined>>;
findRelation(RelationClass: any, relationName: any, dtos: any) {
throw new Error('Not implemented yet');
dto: Entity | Entity[],
): Promise<(Relation | undefined) | Map<Entity, Relation | undefined>> {
const dtos: Entity[] = Array.isArray(dto) ? dto : [dto];
const relationRepo = this.repo.manager.getRepository(RelationClass);
return dtos.reduce(async (prev, curr) => {
const map = await prev;
map.set(curr, await relationRepo.findOne(curr[relationName as keyof Entity]));
return map;
}, Promise.resolve(new Map<Entity, Relation | undefined>()));
}

addRelations<Relation>(relationName: string, id: string | number, relationIds: (string | number)[]): Promise<Entity> {
queryRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
entities: Entity[],
query: Query<Relation>,
): Promise<Map<Entity, Relation[]>>;
queryRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dto: Entity,
query: Query<Relation>,
): Promise<Relation[]>;
queryRelations<Relation>(
RelationClass: Class<Relation>,
relationName: string,
dto: Entity | Entity[],
query: Query<Relation>,
): Promise<Relation[] | Map<Entity, Relation[]>> {
throw new Error('Not implemented yet');
}

setRelation<Relation>(relationName: string, id: string | number, relationId: string | number): Promise<Entity> {
removeRelation<Relation>(relationName: string, id: string | number, relationId: string | number): Promise<Entity> {
throw new Error('Not implemented yet');
}

Expand All @@ -394,7 +439,7 @@ export class TypeOrmMongoQueryService<Entity> implements QueryService<Entity> {
throw new Error('Not implemented yet');
}

removeRelation<Relation>(relationName: string, id: string | number, relationId: string | number): Promise<Entity> {
setRelation<Relation>(relationName: string, id: string | number, relationId: string | number): Promise<Entity> {
throw new Error('Not implemented yet');
}
}

0 comments on commit f4190e6

Please sign in to comment.