Skip to content

Commit

Permalink
feat(typeorm): Implement setRelations to set many relations
Browse files Browse the repository at this point in the history
  • Loading branch information
doug-martin committed Apr 13, 2021
1 parent 4c73591 commit d1109b7
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1171,6 +1171,61 @@ describe('TypeOrmQueryService', (): void => {
});
});

describe('#setRelations', () => {
it('set all relations on the entity', async () => {
const entity = TEST_ENTITIES[0];
const queryService = moduleRef.get(TestEntityService);
const relationIds = TEST_RELATIONS.slice(3, 6).map((r) => r.testRelationPk);
const queryResult = await queryService.setRelations('testRelations', entity.testEntityPk, relationIds);
expect(queryResult).toEqual(entity);

const relations = await queryService.queryRelations(TestRelation, 'testRelations', entity, {});
expect(relations.map((r) => r.testRelationPk)).toEqual(relationIds);
});

it('should remove all relations if the relationIds is empty', async () => {
const entity = TEST_ENTITIES[0];
const queryService = moduleRef.get(TestEntityService);
const queryResult = await queryService.setRelations('testRelations', entity.testEntityPk, []);
expect(queryResult).toEqual(entity);

const relations = await queryService.queryRelations(TestRelation, 'testRelations', entity, {});
expect(relations.map((r) => r.testRelationPk)).toEqual([]);
});

describe('with modify options', () => {
it('should throw an error if the entity is not found with the id and provided filter', async () => {
const entity = TEST_ENTITIES[0];
const queryService = moduleRef.get(TestEntityService);
return expect(
queryService.setRelations(
'testRelations',
entity.testEntityPk,
TEST_RELATIONS.slice(3, 6).map((r) => r.testRelationPk),
{
filter: { stringType: { eq: TEST_ENTITIES[1].stringType } },
},
),
).rejects.toThrow('Unable to find TestEntity with id: test-entity-1');
});

it('should throw an error if the relations are not found with the relationIds and provided filter', async () => {
const entity = TEST_ENTITIES[0];
const queryService = moduleRef.get(TestEntityService);
return expect(
queryService.setRelations<TestRelation>(
'testRelations',
entity.testEntityPk,
TEST_RELATIONS.slice(3, 6).map((r) => r.testRelationPk),
{
relationFilter: { relationName: { like: '%-one' } },
},
),
).rejects.toThrow('Unable to find all testRelations to set on TestEntity');
});
});
});

describe('#setRelation', () => {
it('call select and return the result', async () => {
const entity = TEST_ENTITIES[0];
Expand Down
40 changes: 34 additions & 6 deletions packages/query-typeorm/src/services/relation-query.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,35 @@ export abstract class RelationQueryService<Entity> {
if (!this.foundAllRelations(relationIds, relations)) {
throw new Error(`Unable to find all ${relationName} to add to ${this.EntityClass.name}`);
}
await this.createRelationQueryBuilder(entity, relationName).add(relationIds);
await this.createTypeormRelationQueryBuilder(entity, relationName).add(relationIds);
return entity;
}

/**
* Set the relations on the entity.
*
* @param id - The id of the entity to set the relation on.
* @param relationName - The name of the relation to query for.
* @param relationIds - The ids of the relation to set on the entity. If the relationIds is empty all relations
* will be removed.
* @param opts - Additional options
*/
async setRelations<Relation>(
relationName: string,
id: string | number,
relationIds: (string | number)[],
opts?: ModifyRelationOptions<Entity, Relation>,
): Promise<Entity> {
const entity = await this.getById(id, opts);
const relations = await this.getRelations(relationName, relationIds, opts?.relationFilter);
if (relationIds.length) {
if (!this.foundAllRelations(relationIds, relations)) {
throw new Error(`Unable to find all ${relationName} to set on ${this.EntityClass.name}`);
}
}
const relationQueryBuilder = this.getRelationQueryBuilder(relationName);
const existingRelations = await relationQueryBuilder.select(entity, { filter: opts?.relationFilter }).getMany();
await this.createTypeormRelationQueryBuilder(entity, relationName).addAndRemove(relations, existingRelations);
return entity;
}

Expand All @@ -226,7 +254,7 @@ export abstract class RelationQueryService<Entity> {
if (!relation) {
throw new Error(`Unable to find ${relationName} to set on ${this.EntityClass.name}`);
}
await this.createRelationQueryBuilder(entity, relationName).set(relationId);
await this.createTypeormRelationQueryBuilder(entity, relationName).set(relationId);
return entity;
}

Expand All @@ -248,7 +276,7 @@ export abstract class RelationQueryService<Entity> {
if (!this.foundAllRelations(relationIds, relations)) {
throw new Error(`Unable to find all ${relationName} to remove from ${this.EntityClass.name}`);
}
await this.createRelationQueryBuilder(entity, relationName).remove(relationIds);
await this.createTypeormRelationQueryBuilder(entity, relationName).remove(relationIds);
return entity;
}

Expand All @@ -272,9 +300,9 @@ export abstract class RelationQueryService<Entity> {
}
const meta = this.getRelationMeta(relationName);
if (meta.isOneToOne || meta.isManyToOne) {
await this.createRelationQueryBuilder(entity, relationName).set(null);
await this.createTypeormRelationQueryBuilder(entity, relationName).set(null);
} else {
await this.createRelationQueryBuilder(entity, relationName).remove(relationId);
await this.createTypeormRelationQueryBuilder(entity, relationName).remove(relationId);
}

return entity;
Expand Down Expand Up @@ -399,7 +427,7 @@ export abstract class RelationQueryService<Entity> {
return results;
}

private createRelationQueryBuilder(entity: Entity, relationName: string): TypeOrmRelationQueryBuilder<Entity> {
private createTypeormRelationQueryBuilder(entity: Entity, relationName: string): TypeOrmRelationQueryBuilder<Entity> {
return this.repo.createQueryBuilder().relation(relationName).of(entity);
}

Expand Down

0 comments on commit d1109b7

Please sign in to comment.