metropolis/src/items/items.service.ts

148 lines
4.3 KiB
TypeScript
Raw Normal View History

2021-07-08 19:40:14 +02:00
import { Injectable } from '@nestjs/common';
2021-07-08 23:58:07 +02:00
import { InjectEntityManager, InjectRepository } from '@nestjs/typeorm';
import { EntityManager, Repository, TreeRepository } from 'typeorm';
import assert from 'assert';
2021-07-08 19:40:14 +02:00
import { NewItemInput } from './dto/new-item.input';
2021-07-30 19:05:51 +02:00
import { EditItemInput } from './dto/edit-item.input';
2021-07-21 01:14:20 +02:00
import { EANService } from './ean/ean.service';
2021-07-08 19:40:14 +02:00
import { Item } from './items.entity';
2021-07-21 23:42:11 +02:00
import { ItemModel, PaginatedItems } from './items.model';
2021-07-08 19:40:14 +02:00
@Injectable()
export class ItemsService {
constructor(
@InjectRepository(Item)
private itemRepository: Repository<Item>,
2021-07-08 23:58:07 +02:00
@InjectEntityManager()
private entityManager: EntityManager,
2021-07-21 01:14:20 +02:00
private eans: EANService,
2021-07-08 23:58:07 +02:00
) {
this.treeRepository = this.entityManager.getTreeRepository(Item);
}
treeRepository: TreeRepository<Item>;
2021-07-08 19:40:14 +02:00
async getItem(id: string): Promise<Item | undefined> {
2021-07-21 01:14:20 +02:00
return this.itemRepository.findOne(this.eans.toID(id));
2021-07-08 19:40:14 +02:00
}
2021-07-17 18:34:30 +02:00
async getItemParent(item: ItemModel): Promise<Item | undefined> {
2021-07-21 01:14:20 +02:00
const childItem = await this.itemRepository.findOneOrFail(
this.eans.toID(item.id),
{
relations: ['parent'],
},
);
2021-07-17 17:07:19 +02:00
return childItem.parent;
2021-07-08 23:58:07 +02:00
}
2021-07-20 23:32:48 +02:00
async getItemAncestors(item: ItemModel): Promise<Item[]> {
2021-07-31 19:35:36 +02:00
const id = this.eans.toID(item.id);
const childItem = await this.itemRepository.findOneOrFail(id, {
relations: ['parent'],
});
return (await this.treeRepository.findAncestors(childItem)).filter(
(anc) => anc.id !== id,
2021-07-21 01:14:20 +02:00
);
2021-07-20 23:32:48 +02:00
}
2021-07-17 18:34:30 +02:00
async getItemChildren(item: ItemModel): Promise<Item[]> {
return this.itemRepository.find({
where: {
2021-07-21 01:14:20 +02:00
parent: this.eans.toID(item.id),
2021-07-17 18:34:30 +02:00
},
});
}
2021-07-20 23:34:25 +02:00
async getItemDescendants(item: ItemModel): Promise<Item[]> {
2021-07-31 19:35:36 +02:00
const id = this.eans.toID(item.id);
const parentItem = await this.itemRepository.findOneOrFail(id, {
relations: ['parent'],
});
return (await this.treeRepository.findDescendants(parentItem)).filter(
(des) => des.id !== id,
2021-07-21 01:14:20 +02:00
);
}
2021-07-21 23:42:11 +02:00
async getItemList(cursor: number = 0): Promise<PaginatedItems> {
const [items, count] = await this.itemRepository.findAndCount({
2021-08-01 22:39:36 +02:00
order: { id: 'ASC' },
2021-07-21 23:42:11 +02:00
take: 25,
skip: cursor,
});
return {
nodes: items,
cursor: cursor + items.length,
totalCount: count,
hasNextPage: count > cursor + items.length,
};
}
2021-07-08 19:40:14 +02:00
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
2021-07-21 01:14:20 +02:00
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';
2021-07-17 16:44:34 +02:00
const item = this.itemRepository.create({
...input,
// if id not provided, use the highest one in db +1
2021-07-21 01:14:20 +02:00
id: highestId
? (BigInt(highestId) + 1n).toString(10)
: // @ts-ignore input.id must exist here
this.eans.toID(input.id),
name: input.name.trim(),
notes: input.notes ? input.notes.trim() || undefined : undefined,
2021-07-17 16:44:34 +02:00
parent: input.parent
? await this.itemRepository.findOneOrFail(this.eans.toID(input.parent))
2021-07-17 16:44:34 +02:00
: undefined,
});
assert(item.name.length > 0, 'You must provide item name');
await this.itemRepository.save(item);
2021-07-17 16:44:34 +02:00
return item;
2021-07-08 19:40:14 +02:00
}
2021-07-29 02:12:46 +02:00
2021-07-30 19:05:51 +02:00
async editItem(input: EditItemInput) {
const item = await this.itemRepository.findOneOrFail(
this.eans.toID(input.id),
);
const edited: Item = {
...item,
...input,
// input.id can be an EAN-13
id: item.id,
parent: input.parent
? await this.itemRepository.findOneOrFail(this.eans.toID(input.parent))
: undefined,
};
await this.itemRepository.save(edited);
return edited;
}
2021-07-29 02:12:46 +02:00
async deleteItem(id: string) {
const item = await this.itemRepository.findOne(this.eans.toID(id));
if (!item) {
return null;
}
// will fail if item has children
await this.itemRepository.remove(item);
return item;
}
2021-07-08 19:40:14 +02:00
}