metropolis/src/items/items.service.ts

103 lines
3.0 KiB
TypeScript

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<Item>,
@InjectEntityManager()
private entityManager: EntityManager,
private eans: EANService,
) {
this.treeRepository = this.entityManager.getTreeRepository(Item);
}
treeRepository: TreeRepository<Item>;
async getItem(id: string): Promise<Item | undefined> {
return this.itemRepository.findOne(this.eans.toID(id));
}
async getItemParent(item: ItemModel): Promise<Item | undefined> {
const childItem = await this.itemRepository.findOneOrFail(
this.eans.toID(item.id),
{
relations: ['parent'],
},
);
return childItem.parent;
}
async getItemAncestors(item: ItemModel): Promise<Item[]> {
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<Item[]> {
return this.itemRepository.find({
where: {
parent: this.eans.toID(item.id),
},
});
}
async getItemDescendants(item: ItemModel): Promise<Item[]> {
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<Item> {
// 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;
}
}