import { Injectable } from '@nestjs/common'; import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm'; import { EntityManager, Repository, TreeRepository } from 'typeorm'; import { NewItemInput } from './dto/new-item.input'; import { EANService } from './ean/ean.service'; import { Item } from './items.entity'; import { ItemModel } from './items.model'; @Injectable() export class ItemsService { constructor( @InjectRepository(Item) private itemRepository: Repository, @InjectEntityManager() private entityManager: EntityManager, private eans: EANService, ) { this.treeRepository = this.entityManager.getTreeRepository(Item); } treeRepository: TreeRepository; async getItem(id: string): Promise { return this.itemRepository.findOne(this.eans.toID(id)); } async getItemParent(item: ItemModel): Promise { const childItem = await this.itemRepository.findOneOrFail( this.eans.toID(item.id), { relations: ['parent'], }, ); return childItem.parent; } async getItemAncestors(item: ItemModel): Promise { const childItem = await this.itemRepository.findOneOrFail( this.eans.toID(item.id), { relations: ['parent'], }, ); // TreeRepository.findAncestors()[-1] is always the child item itself return (await this.treeRepository.findAncestors(childItem)).slice(0, -1); } async getItemChildren(item: ItemModel): Promise { return this.itemRepository.find({ where: { parent: this.eans.toID(item.id), }, }); } async getItemDescendants(item: ItemModel): Promise { const parentItem = await this.itemRepository.findOneOrFail( this.eans.toID(item.id), { relations: ['parent'], }, ); // TreeRepository.findDescendants()[0] is always the parent item return (await this.treeRepository.findDescendants(parentItem)).slice(1); } async createItem(input: NewItemInput): Promise { // must use Repository.save() for the closure table to work, // so we have to check whether the provided ID exists in the first place if ( input.id && (await this.itemRepository.count({ id: this.eans.toID(input.id) })) !== 0 ) { throw new Error('Item with this ID already exists'); } const highestId = input.id ? // nobody cares in this case null : ( await this.itemRepository.findOne({ select: ['id'], order: { id: 'DESC' }, }) )?.id || '139999999999'; const item = this.itemRepository.create({ ...input, // if id not provided, use the highest one in db +1 id: highestId ? (BigInt(highestId) + 1n).toString(10) : // @ts-ignore input.id must exist here this.eans.toID(input.id), parent: input.parent ? await this.itemRepository.findOneOrFail(input.parent) : undefined, }); await this.itemRepository.save(item); return item; } }