Skip to content

Commit

Permalink
Server: Track Service: allow getting many by slug or id + allow delet…
Browse files Browse the repository at this point in the history
…ing many
  • Loading branch information
Arthi-chaud committed Jan 10, 2025
1 parent a0892e6 commit c2cf97e
Show file tree
Hide file tree
Showing 11 changed files with 90 additions and 81 deletions.
6 changes: 2 additions & 4 deletions server/src/file/file.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,8 @@ export default class FileController {
@Role(Roles.Admin, Roles.Microservice)
@Delete()
async deleteMany(@Body() toDelete: FileDeletionDto) {
await Promise.all(
toDelete.ids.map((fileId) =>
this.registrationService.unregisterFile({ id: fileId }),
),
await this.registrationService.unregisterFiles(
toDelete.ids.map((id) => ({ id })),
);
await this.housekeepingService.runHousekeeping();
}
Expand Down
7 changes: 1 addition & 6 deletions server/src/file/file.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,9 @@ describe("File Service", () => {

describe("Delete File", () => {
it("should delete a file (from id)", async () => {
await fileService.delete({ id: newFile.id });
await fileService.delete([{ id: newFile.id }]);
const test = async () => fileService.get({ id: newFile.id });
return expect(test()).rejects.toThrow(FileNotFoundException);
});

it("should throw, as the file does not exist (from id)", () => {
const test = async () => fileService.delete({ id: -1 });
return expect(test()).rejects.toThrow(FileNotFoundException);
});
});
});
20 changes: 10 additions & 10 deletions server/src/file/file.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,12 @@ export default class FileService {
static formatManyWhereInput(where: FileQueryParameters.ManyWhereInput) {
let query: Prisma.FileWhereInput = {};

if (where.id) {
query = deepmerge(query, { id: where.id });
if (where.files) {
query = deepmerge(query, {
OR: where.files.map((file) =>
FileService.formatWhereInput(file),
),
});
}
if (where.library) {
query = deepmerge<Prisma.FileWhereInput>(query, {
Expand Down Expand Up @@ -238,13 +242,9 @@ export default class FileService {
return `${libraryPath}/${file.path}`.normalize();
}

async delete(where: FileQueryParameters.DeleteInput) {
return this.prismaService.file
.delete({
where: FileService.formatWhereInput(where),
})
.catch((error) => {
throw this.onNotFound(error, where);
});
async delete(where: FileQueryParameters.DeleteInput[]) {
return this.prismaService.file.deleteMany({
where: FileService.formatManyWhereInput({ files: where }),
});
}
}
2 changes: 1 addition & 1 deletion server/src/file/models/file.query-parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace FileQueryParameters {
release: ReleaseQueryParameters.WhereInput;
song: SongQueryParameters.WhereInput;
track: TrackQueryParameters.WhereInput;
id: { in: File["id"][] };
files: FileQueryParameters.WhereInput[];
paths: File["path"][];
registrationDate: SearchDateInput;
}>
Expand Down
6 changes: 2 additions & 4 deletions server/src/library/library.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,10 +184,8 @@ export default class LibraryService {
async delete(where: LibraryQueryParameters.WhereInput): Promise<Library> {
const relatedFiles = await this.fileService.getMany({ library: where });

await Promise.all(
relatedFiles.map((file) =>
this.registrationService.unregisterFile({ id: file.id }),
),
await this.registrationService.unregisterFiles(
relatedFiles.map((file) => ({ id: file.id })),
);
await this.housekeepingService.runHousekeeping();
return this.prismaService.library
Expand Down
2 changes: 1 addition & 1 deletion server/src/registration/metadata.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ export default class MetadataService {
}
}
if (overwrite) {
await this.trackService.delete({ sourceFileId: file.id });
await this.trackService.delete([{ sourceFileId: file.id }]);
}
return this.trackService.create(track).then(async (res) => {
if (
Expand Down
14 changes: 9 additions & 5 deletions server/src/registration/registration.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ export class RegistrationService {
releaseId: createdTrack.releaseId,
};
} catch (e) {
await this.fileService.delete({ id: fileEntry.id });
await this.fileService.delete([{ id: fileEntry.id }]);
throw e;
}
}
Expand Down Expand Up @@ -128,17 +128,21 @@ export class RegistrationService {
};
}

public async unregisterFile(
where: FileQueryParameters.DeleteInput,
public async unregisterFiles(
where: FileQueryParameters.DeleteInput[],
housekeeping = false,
) {
await this.trackService
.delete({ sourceFileId: where.id })
const deletedTrackCount = await this.trackService
.delete(where.map(({ id: sourceFileId }) => ({ sourceFileId })))
.catch((error) => {
if (!(error instanceof NotFoundException)) {
throw error;
}
return 0;
});
if (deletedTrackCount) {
this.logger.warn(`Deleted ${deletedTrackCount} tracks`);
}
await this.fileService.delete(where);
if (housekeeping) {
await this.housekeepingService.runHousekeeping();
Expand Down
3 changes: 1 addition & 2 deletions server/src/release/release.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createTestingModule } from "test/test-module";
import type { TestingModule } from "@nestjs/testing";
import type { Release } from "src/prisma/models";
import { AlbumNotFoundException } from "src/album/album.exceptions";
import AlbumModule from "src/album/album.module";
import AlbumService from "src/album/album.service";
import ArtistModule from "src/artist/artist.module";
Expand Down Expand Up @@ -304,7 +303,7 @@ describe("Release Service", () => {
);
});
it("should delete the master release", async () => {
await trackService.delete({ id: dummyRepository.trackB1_1.id });
await trackService.delete([{ id: dummyRepository.trackB1_1.id }]);
await albumService.update(
{
master: { id: dummyRepository.releaseB1_1.id },
Expand Down
2 changes: 1 addition & 1 deletion server/src/track/models/track.query-parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace TrackQueryParameters {
RequireAtLeastOne<
{
type: TrackType;
id: { in: number[] };
tracks: TrackQueryParameters.WhereInput[];
song: SongQueryParameters.WhereInput;
video: VideoQueryParameters.WhereInput;
library: LibraryQueryParameters.WhereInput;
Expand Down
4 changes: 2 additions & 2 deletions server/src/track/track.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,7 @@ describe("Track Service", () => {
const track = await trackService.getSongMasterTrack({
id: dummyRepository.songA1.id,
});
await trackService.delete({ id: tmpTrack.id });
await trackService.delete([{ id: tmpTrack.id }]);
await releaseService.delete([{ id: tmpRelease.id }]);
expect(track).toStrictEqual(dummyRepository.trackA1_1);
});
Expand Down Expand Up @@ -487,7 +487,7 @@ describe("Track Service", () => {
},
{ id: dummyRepository.songA1.id },
);
await trackService.delete({ id: dummyRepository.trackA1_1.id });
await trackService.delete([{ id: dummyRepository.trackA1_1.id }]);

const test = async () =>
await trackService.get({ id: dummyRepository.trackA1_1.id });
Expand Down
105 changes: 60 additions & 45 deletions server/src/track/track.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,14 @@ import {
TrackNotFoundException,
} from "./track.exceptions";
import ReleaseService from "src/release/release.service";
import type TrackQueryParameters from "./models/track.query-parameters";
import TrackQueryParameters from "./models/track.query-parameters";
import type ReleaseQueryParameters from "src/release/models/release.query-parameters";
import type SongQueryParameters from "src/song/models/song.query-params";
import FileService from "src/file/file.service";
import Slug from "src/slug/slug";
import AlbumService from "src/album/album.service";
import LibraryService from "src/library/library.service";
import { Track } from "src/prisma/models";
import Identifier from "src/identifier/models/identifier";
import Logger from "src/logger/logger";
import { PrismaError } from "prisma-error-enum";
import { FileNotFoundException } from "src/file/file.exceptions";
import IllustrationRepository from "src/illustration/illustration.repository";
Expand All @@ -51,7 +49,6 @@ import VideoService from "src/video/video.service";

@Injectable()
export default class TrackService {
private readonly logger = new Logger(TrackService.name);
constructor(
@Inject(forwardRef(() => SongService))
private songService: SongService,
Expand Down Expand Up @@ -186,8 +183,12 @@ export default class TrackService {
type: where.type,
};

if (where.id) {
queryParameters = deepmerge(queryParameters, { id: where.id });
if (where.tracks) {
queryParameters = deepmerge(queryParameters, {
OR: where.tracks.map((track) =>
TrackService.formatWhereInput(track),
),
});
}
if (where.song) {
queryParameters = deepmerge(queryParameters, {
Expand Down Expand Up @@ -501,47 +502,61 @@ export default class TrackService {
}

/**
* Deletes a track
* @param where Query parameters to find the track to delete
* Delete tracks
* @param where Query parameters to find the tracks to delete
*/
async delete(where: TrackQueryParameters.DeleteInput): Promise<Track> {
return this.prismaService.track
.delete({
where: where,
})
.then((deleted) => {
if (deleted.thumbnailId) {
this.illustrationRepository.deleteIllustration(
deleted.thumbnailId,
);
}
if (deleted.releaseId) {
this.illustrationRepository
.getReleaseIllustrations({ id: deleted.releaseId })
.then((relatedIllustrations) => {
const exactIllustration = relatedIllustrations.find(
(i) =>
i.disc !== null &&
i.track !== null &&
i.disc === deleted.discIndex &&
i.track === deleted.trackIndex,
);
if (exactIllustration) {
this.illustrationRepository.deleteIllustration(
exactIllustration.id,
);
}
});
}
this.logger.warn(`Track '${deleted.name}' deleted`);
return deleted;
})
.catch((error) => {
throw this.onNotFound(
error,
this.formatDeleteInputToWhereInput(where),
);
async delete(where: TrackQueryParameters.DeleteInput[]): Promise<number> {
const chunkSize = 30;
let totalDeleted = 0;
for (let idx = 0; idx < where.length; idx += chunkSize) {
const whereChunk = where
.slice(idx, idx + chunkSize)
.map((track) => this.formatDeleteInputToWhereInput(track));

const toDelete = await this.getMany({
tracks: whereChunk,
});
await Promise.allSettled(
toDelete
.filter(({ thumbnailId }) => thumbnailId !== null)
.map(({ thumbnailId }) =>
this.illustrationRepository.deleteIllustration(
thumbnailId!,
),
),
);

await Promise.allSettled(
toDelete
.filter(({ releaseId }) => releaseId !== null)
.map(({ releaseId, discIndex, trackIndex }) =>
this.illustrationRepository
.getReleaseIllustrations({ id: releaseId! })
.then(async (relatedIllustrations) => {
const exactIllustration =
relatedIllustrations.find(
(i) =>
i.disc !== null &&
i.track !== null &&
i.disc === discIndex &&
i.track === trackIndex,
);
if (exactIllustration) {
await this.illustrationRepository.deleteIllustration(
exactIllustration.id,
);
}
}),
),
);
const deleted = await this.prismaService.track.deleteMany({
where: TrackService.formatManyWhereInput({
tracks: whereChunk,
}),
});
totalDeleted = totalDeleted + deleted.count;
}
return totalDeleted;
}

/**
Expand Down

0 comments on commit c2cf97e

Please sign in to comment.