refactor(server): stacks (#11453)

* refactor: stacks

* mobile: get it built

* chore: feedback

* fix: sync and duplicates

* mobile: remove old stack reference

* chore: add primary asset id

* revert change to asset entity

* mobile: refactor mobile api

* mobile: sync stack info after creating stack

* mobile: update timeline after deleting stack

* server: update asset updatedAt when stack is deleted

* mobile: simplify action

* mobile: rename to match dto property

* fix: web test

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Jason Rasmussen
2024-08-19 13:37:15 -04:00
committed by GitHub
parent ca52cbace1
commit 8338657eaa
63 changed files with 2321 additions and 1152 deletions

View File

@@ -1,21 +1,120 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { AssetEntity } from 'src/entities/asset.entity';
import { StackEntity } from 'src/entities/stack.entity';
import { IStackRepository } from 'src/interfaces/stack.interface';
import { IStackRepository, StackSearch } from 'src/interfaces/stack.interface';
import { Instrumentation } from 'src/utils/instrumentation';
import { Repository } from 'typeorm';
import { DataSource, In, Repository } from 'typeorm';
@Instrumentation()
@Injectable()
export class StackRepository implements IStackRepository {
constructor(@InjectRepository(StackEntity) private repository: Repository<StackEntity>) {}
constructor(
@InjectDataSource() private dataSource: DataSource,
@InjectRepository(StackEntity) private repository: Repository<StackEntity>,
) {}
create(entity: Partial<StackEntity>) {
return this.save(entity);
search(query: StackSearch): Promise<StackEntity[]> {
return this.repository.find({
where: {
ownerId: query.ownerId,
primaryAssetId: query.primaryAssetId,
},
relations: {
assets: {
exifInfo: true,
},
},
});
}
async create(entity: { ownerId: string; assetIds: string[] }): Promise<StackEntity> {
return this.dataSource.manager.transaction(async (manager) => {
const stackRepository = manager.getRepository(StackEntity);
const stacks = await stackRepository.find({
where: {
ownerId: entity.ownerId,
primaryAssetId: In(entity.assetIds),
},
select: {
id: true,
assets: {
id: true,
},
},
relations: {
assets: {
exifInfo: true,
},
},
});
const assetIds = new Set<string>(entity.assetIds);
// children
for (const stack of stacks) {
for (const asset of stack.assets) {
assetIds.add(asset.id);
}
}
if (stacks.length > 0) {
await stackRepository.delete({ id: In(stacks.map((stack) => stack.id)) });
}
const { id } = await stackRepository.save({
ownerId: entity.ownerId,
primaryAssetId: entity.assetIds[0],
assets: [...assetIds].map((id) => ({ id }) as AssetEntity),
});
return stackRepository.findOneOrFail({
where: {
id,
},
relations: {
assets: {
exifInfo: true,
},
},
});
});
}
async delete(id: string): Promise<void> {
const stack = await this.getById(id);
if (!stack) {
return;
}
const assetIds = stack.assets.map(({ id }) => id);
await this.repository.delete(id);
// Update assets updatedAt
await this.dataSource.manager.update(AssetEntity, assetIds, {
updatedAt: new Date(),
});
}
async deleteAll(ids: string[]): Promise<void> {
const assetIds = [];
for (const id of ids) {
const stack = await this.getById(id);
if (!stack) {
continue;
}
assetIds.push(...stack.assets.map(({ id }) => id));
}
await this.repository.delete(ids);
// Update assets updatedAt
await this.dataSource.manager.update(AssetEntity, assetIds, {
updatedAt: new Date(),
});
}
update(entity: Partial<StackEntity>) {
@@ -28,8 +127,14 @@ export class StackRepository implements IStackRepository {
id,
},
relations: {
primaryAsset: true,
assets: true,
assets: {
exifInfo: true,
},
},
order: {
assets: {
fileCreatedAt: 'ASC',
},
},
});
}
@@ -41,8 +146,14 @@ export class StackRepository implements IStackRepository {
id,
},
relations: {
primaryAsset: true,
assets: true,
assets: {
exifInfo: true,
},
},
order: {
assets: {
fileCreatedAt: 'ASC',
},
},
});
}