refactor: migrate memory to kysely (#15314)

This commit is contained in:
Jason Rasmussen
2025-01-15 11:34:11 -05:00
committed by GitHub
parent 43b3181f45
commit 93e2545275
5 changed files with 177 additions and 89 deletions

View File

@@ -1,49 +1,55 @@
import { Injectable } from '@nestjs/common';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { Insertable, Kysely, Updateable } from 'kysely';
import { jsonArrayFrom } from 'kysely/helpers/postgres';
import { InjectKysely } from 'nestjs-kysely';
import { DB, Memories } from 'src/db';
import { Chunked, ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
import { MemoryEntity } from 'src/entities/memory.entity';
import { IMemoryRepository } from 'src/interfaces/memory.interface';
import { DataSource, In, Repository } from 'typeorm';
@Injectable()
export class MemoryRepository implements IMemoryRepository {
constructor(
@InjectRepository(MemoryEntity) private repository: Repository<MemoryEntity>,
@InjectDataSource() private dataSource: DataSource,
) {}
constructor(@InjectKysely() private db: Kysely<DB>) {}
@GenerateSql({ params: [DummyValue.UUID] })
search(ownerId: string): Promise<MemoryEntity[]> {
return this.repository.find({
where: {
ownerId,
},
order: {
memoryAt: 'DESC',
},
});
return this.db
.selectFrom('memories')
.selectAll()
.where('ownerId', '=', ownerId)
.orderBy('memoryAt', 'desc')
.execute() as Promise<MemoryEntity[]>;
}
@GenerateSql({ params: [DummyValue.UUID] })
get(id: string): Promise<MemoryEntity | null> {
return this.repository.findOne({
where: {
id,
},
relations: {
assets: true,
},
return this.getByIdBuilder(id).executeTakeFirst() as unknown as Promise<MemoryEntity | null>;
}
async create(memory: Insertable<Memories>, assetIds: Set<string>): Promise<MemoryEntity> {
const id = await this.db.transaction().execute(async (tx) => {
const { id } = await tx.insertInto('memories').values(memory).returning('id').executeTakeFirstOrThrow();
if (assetIds.size > 0) {
const values = [...assetIds].map((assetId) => ({ memoriesId: id, assetsId: assetId }));
await tx.insertInto('memories_assets_assets').values(values).execute();
}
return id;
});
return this.getByIdBuilder(id).executeTakeFirstOrThrow() as unknown as Promise<MemoryEntity>;
}
create(memory: Partial<MemoryEntity>): Promise<MemoryEntity> {
return this.save(memory);
}
update(memory: Partial<MemoryEntity>): Promise<MemoryEntity> {
return this.save(memory);
@GenerateSql({ params: [DummyValue.UUID, { ownerId: DummyValue.UUID, isSaved: true }] })
async update(id: string, memory: Updateable<Memories>): Promise<MemoryEntity> {
await this.db.updateTable('memories').set(memory).where('id', '=', id).execute();
return this.getByIdBuilder(id).executeTakeFirstOrThrow() as unknown as Promise<MemoryEntity>;
}
@GenerateSql({ params: [DummyValue.UUID] })
async delete(id: string): Promise<void> {
await this.repository.delete({ id });
await this.db.deleteFrom('memories').where('id', '=', id).execute();
}
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
@@ -53,46 +59,49 @@ export class MemoryRepository implements IMemoryRepository {
return new Set();
}
const results = await this.dataSource
.createQueryBuilder()
.select('memories_assets.assetsId', 'assetId')
.from('memories_assets_assets', 'memories_assets')
.where('"memories_assets"."memoriesId" = :memoryId', { memoryId: id })
.andWhere('memories_assets.assetsId IN (:...assetIds)', { assetIds })
.getRawMany<{ assetId: string }>();
const results = await this.db
.selectFrom('memories_assets_assets')
.select(['assetsId'])
.where('memoriesId', '=', id)
.where('assetsId', 'in', assetIds)
.execute();
return new Set(results.map(({ assetId }) => assetId));
return new Set(results.map(({ assetsId }) => assetsId));
}
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
async addAssetIds(id: string, assetIds: string[]): Promise<void> {
await this.dataSource
.createQueryBuilder()
.insert()
.into('memories_assets_assets', ['memoriesId', 'assetsId'])
await this.db
.insertInto('memories_assets_assets')
.values(assetIds.map((assetId) => ({ memoriesId: id, assetsId: assetId })))
.execute();
}
@Chunked({ paramIndex: 1 })
@GenerateSql({ params: [DummyValue.UUID, [DummyValue.UUID]] })
async removeAssetIds(id: string, assetIds: string[]): Promise<void> {
await this.dataSource
.createQueryBuilder()
.delete()
.from('memories_assets_assets')
.where({
memoriesId: id,
assetsId: In(assetIds),
})
await this.db
.deleteFrom('memories_assets_assets')
.where('memoriesId', '=', id)
.where('assetsId', 'in', assetIds)
.execute();
}
private async save(memory: Partial<MemoryEntity>): Promise<MemoryEntity> {
const { id } = await this.repository.save(memory);
return this.repository.findOneOrFail({
where: { id },
relations: {
assets: true,
},
});
private getByIdBuilder(id: string) {
return this.db
.selectFrom('memories')
.selectAll('memories')
.select((eb) =>
jsonArrayFrom(
eb
.selectFrom('assets')
.selectAll('assets')
.innerJoin('memories_assets_assets', 'assets.id', 'memories_assets_assets.assetsId')
.whereRef('memories_assets_assets.memoriesId', '=', 'memories.id')
.where('assets.deletedAt', 'is', null),
).as('assets'),
)
.where('id', '=', id)
.where('deletedAt', 'is', null);
}
}