add relations
This commit is contained in:
parent
a95cc267ef
commit
8f87c713dc
114
src/modules/content/repositories/category.repository.ts
Normal file
114
src/modules/content/repositories/category.repository.ts
Normal file
@ -0,0 +1,114 @@
|
||||
import { pick, unset } from 'lodash';
|
||||
import { FindOptionsUtils, FindTreeOptions, TreeRepository, TreeRepositoryUtils } from 'typeorm';
|
||||
|
||||
import { CategoryEntity } from '@/modules/content/entities/CategoryEntity';
|
||||
import { CustomRepository } from '@/modules/database/decorators/repository.decorator';
|
||||
|
||||
@CustomRepository(CategoryEntity)
|
||||
export class CategoryRepository extends TreeRepository<CategoryEntity> {
|
||||
buildBaseQB() {
|
||||
return this.createQueryBuilder('category').leftJoinAndSelect('category.parent', 'parent');
|
||||
}
|
||||
|
||||
async findTrees(options?: FindTreeOptions) {
|
||||
const roots = await this.findRoots(options);
|
||||
await Promise.all(roots.map((root) => this.findDescendantsTree(root, options)));
|
||||
return roots;
|
||||
}
|
||||
|
||||
findRoots(options?: FindTreeOptions): Promise<CategoryEntity[]> {
|
||||
const escape = (val: string) => this.manager.connection.driver.escape(val);
|
||||
const joinColumn = this.metadata.treeParentRelation!.joinColumns[0];
|
||||
const parentPropertyName = joinColumn.givenDatabaseName || joinColumn.databaseName;
|
||||
const qb = this.buildBaseQB().orderBy('category.customOrder', 'ASC');
|
||||
FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, options);
|
||||
return qb.where(`${escape('category')}.${escape(parentPropertyName)} IS NULL`).getMany();
|
||||
}
|
||||
|
||||
findDescendants(entity: CategoryEntity, options?: FindTreeOptions): Promise<CategoryEntity[]> {
|
||||
const qb = this.createDescendantsQueryBuilder('category', 'treeClosure', entity);
|
||||
FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, options);
|
||||
qb.orderBy('category.customOrder', 'ASC');
|
||||
return qb.getMany();
|
||||
}
|
||||
|
||||
findAncestors(entity: CategoryEntity, options?: FindTreeOptions): Promise<CategoryEntity[]> {
|
||||
const qb = this.createAncestorsQueryBuilder('category', 'treeClosure', entity);
|
||||
FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, options);
|
||||
qb.orderBy('category.customOrder', 'ASC');
|
||||
return qb.getMany();
|
||||
}
|
||||
|
||||
async findDescendantsTree(entity: CategoryEntity, options?: FindTreeOptions) {
|
||||
const qb = this.createDescendantsQueryBuilder('category', 'treeClosure', entity)
|
||||
.leftJoinAndSelect('category.parent', 'parent')
|
||||
.orderBy('category.customOrder', 'ASC');
|
||||
FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, pick(options, ['relations', 'depth']));
|
||||
const entities = await qb.getRawAndEntities();
|
||||
const relationMaps = TreeRepositoryUtils.createRelationMaps(
|
||||
this.manager,
|
||||
this.metadata,
|
||||
'category',
|
||||
entities.raw,
|
||||
);
|
||||
TreeRepositoryUtils.buildChildrenEntityTree(
|
||||
this.metadata,
|
||||
entity,
|
||||
entities.entities,
|
||||
relationMaps,
|
||||
{ depth: -1, ...pick(options, ['relations']) },
|
||||
);
|
||||
return entity;
|
||||
}
|
||||
|
||||
async findAncestorsTree(
|
||||
entity: CategoryEntity,
|
||||
options?: FindTreeOptions,
|
||||
): Promise<CategoryEntity> {
|
||||
const qb = this.createAncestorsQueryBuilder('category', 'treeClosure', entity)
|
||||
.leftJoinAndSelect('category.parent', 'parent')
|
||||
.orderBy('category.customOrder', 'ASC');
|
||||
FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, options);
|
||||
const entities = await qb.getRawAndEntities();
|
||||
const relationMaps = TreeRepositoryUtils.createRelationMaps(
|
||||
this.manager,
|
||||
this.metadata,
|
||||
'category',
|
||||
entities.raw,
|
||||
);
|
||||
TreeRepositoryUtils.buildParentEntityTree(
|
||||
this.metadata,
|
||||
entity,
|
||||
entities.entities,
|
||||
relationMaps,
|
||||
);
|
||||
return entity;
|
||||
}
|
||||
|
||||
async countDescendants(entity: CategoryEntity): Promise<number> {
|
||||
const qb = this.createDescendantsQueryBuilder('category', 'treeClosure', entity);
|
||||
return qb.getCount();
|
||||
}
|
||||
|
||||
async countAncestors(entity: CategoryEntity) {
|
||||
const qb = this.createAncestorsQueryBuilder('category', 'treeClosure', entity);
|
||||
return qb.getCount();
|
||||
}
|
||||
|
||||
async toFlatTrees(
|
||||
trees: CategoryEntity[],
|
||||
depth = 0,
|
||||
parent: CategoryEntity | null = null,
|
||||
): Promise<CategoryEntity[]> {
|
||||
const data: Omit<CategoryEntity, 'children'>[] = [];
|
||||
for (const item of trees) {
|
||||
item.depth = depth;
|
||||
item.parent = parent;
|
||||
const { children } = item;
|
||||
unset(item, 'children');
|
||||
data.push(item);
|
||||
data.push(...(await this.toFlatTrees(children, depth + 1, item)));
|
||||
}
|
||||
return data as CategoryEntity[];
|
||||
}
|
||||
}
|
95
src/modules/content/repositories/comment.repository.ts
Normal file
95
src/modules/content/repositories/comment.repository.ts
Normal file
@ -0,0 +1,95 @@
|
||||
import { pick, unset } from 'lodash';
|
||||
import {
|
||||
FindOptionsUtils,
|
||||
FindTreeOptions,
|
||||
SelectQueryBuilder,
|
||||
TreeRepository,
|
||||
TreeRepositoryUtils,
|
||||
} from 'typeorm';
|
||||
|
||||
import { CommentEntity } from '@/modules/content/entities/comment.entity';
|
||||
import { CustomRepository } from '@/modules/database/decorators/repository.decorator';
|
||||
|
||||
type FindCommentTreeOptions = FindTreeOptions & {
|
||||
addQuery?: (query: SelectQueryBuilder<CommentEntity>) => SelectQueryBuilder<CommentEntity>;
|
||||
};
|
||||
@CustomRepository(CommentEntity)
|
||||
export class CommentRepository extends TreeRepository<CommentEntity> {
|
||||
buildBaseQB(qb: SelectQueryBuilder<CommentEntity>): SelectQueryBuilder<CommentEntity> {
|
||||
return qb
|
||||
.leftJoinAndSelect(`comment.parent`, 'parent')
|
||||
.leftJoinAndSelect(`comment.post`, `post`)
|
||||
.orderBy('comment.createdAt', 'DESC');
|
||||
}
|
||||
|
||||
async findTrees(options: FindCommentTreeOptions): Promise<CommentEntity[]> {
|
||||
options.relations = ['parent', 'children'];
|
||||
const roots = await this.findRoots(options);
|
||||
await Promise.all(roots.map((root) => this.findDescendantsTree(root, options)));
|
||||
return roots;
|
||||
}
|
||||
|
||||
findRoots(options?: FindCommentTreeOptions): Promise<CommentEntity[]> {
|
||||
const { addQuery, ...rest } = options;
|
||||
const escape = (val: string) => this.manager.connection.driver.escape(val);
|
||||
const joinColumn = this.metadata.treeParentRelation!.joinColumns[0];
|
||||
const parentPropertyName = joinColumn.givenDatabaseName || joinColumn.databaseName;
|
||||
|
||||
let qb = this.buildBaseQB(this.createQueryBuilder('comment'));
|
||||
FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, rest);
|
||||
qb.where(`${escape('comment')}.${escape(parentPropertyName)} IS NULL`);
|
||||
qb = addQuery ? addQuery(qb) : qb;
|
||||
return qb.getMany();
|
||||
}
|
||||
|
||||
createDtsQueryBuilder(
|
||||
closureTable: string,
|
||||
entity: CommentEntity,
|
||||
options: FindCommentTreeOptions = {},
|
||||
): SelectQueryBuilder<CommentEntity> {
|
||||
const { addQuery } = options;
|
||||
const qb = this.buildBaseQB(
|
||||
super.createDescendantsQueryBuilder('comment', closureTable, entity),
|
||||
);
|
||||
return addQuery ? addQuery(qb) : qb;
|
||||
}
|
||||
|
||||
async findDescendantsTree(
|
||||
entity: CommentEntity,
|
||||
options: FindCommentTreeOptions = {},
|
||||
): Promise<CommentEntity> {
|
||||
const qb: SelectQueryBuilder<CommentEntity> = this.createDtsQueryBuilder(
|
||||
'treeClosure',
|
||||
entity,
|
||||
options,
|
||||
);
|
||||
FindOptionsUtils.applyOptionsToTreeQueryBuilder(qb, pick(options, ['relations', 'depth']));
|
||||
const entities = await qb.getRawAndEntities();
|
||||
const relationMaps = TreeRepositoryUtils.createRelationMaps(
|
||||
this.manager,
|
||||
this.metadata,
|
||||
'comment',
|
||||
entities.raw,
|
||||
);
|
||||
TreeRepositoryUtils.buildChildrenEntityTree(
|
||||
this.metadata,
|
||||
entity,
|
||||
entities.entities,
|
||||
relationMaps,
|
||||
{ depth: -1, ...pick(options, ['relations']) },
|
||||
);
|
||||
return entity;
|
||||
}
|
||||
|
||||
async toFlatTrees(trees: CommentEntity[], depth = 0): Promise<CommentEntity[]> {
|
||||
const data: Omit<CommentEntity, 'children'>[] = [];
|
||||
for (const item of trees) {
|
||||
item.depth = depth;
|
||||
const { children } = item;
|
||||
unset(item, 'children');
|
||||
data.push(item);
|
||||
data.push(...(await this.toFlatTrees(children, depth + 1)));
|
||||
}
|
||||
return data as CommentEntity[];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user