mirror of
https://github.com/Dictionarry-Hub/profilarr.git
synced 2026-01-28 13:30:56 +01:00
fix: use name+tmdbid primary key instead of auto incmremented id
This commit is contained in:
@@ -33,7 +33,7 @@ export async function getAllConditionsForEvaluation(
|
||||
// Get all conditions for all formats
|
||||
const conditions = await db
|
||||
.selectFrom('custom_format_conditions')
|
||||
.select(['id', 'custom_format_id', 'name', 'type', 'negate', 'required'])
|
||||
.select(['id', 'custom_format_id', 'name', 'type', 'arr_type', 'negate', 'required'])
|
||||
.execute();
|
||||
|
||||
if (conditions.length === 0) {
|
||||
@@ -198,6 +198,7 @@ export async function getAllConditionsForEvaluation(
|
||||
id: c.id,
|
||||
name: c.name,
|
||||
type: c.type,
|
||||
arrType: c.arr_type as 'all' | 'radarr' | 'sonarr',
|
||||
negate: c.negate === 1,
|
||||
required: c.required === 1,
|
||||
patterns: patternsMap.get(c.id),
|
||||
|
||||
@@ -6,7 +6,8 @@ import type { PCDCache } from '../../cache.ts';
|
||||
import { writeOperation, type OperationLayer } from '../../writer.ts';
|
||||
|
||||
export interface CreateTestReleaseInput {
|
||||
entityId: number;
|
||||
entityType: 'movie' | 'series';
|
||||
entityTmdbId: number;
|
||||
title: string;
|
||||
size_bytes: number | null;
|
||||
languages: string[];
|
||||
@@ -31,7 +32,8 @@ export async function createRelease(options: CreateTestReleaseOptions) {
|
||||
const insertRelease = db
|
||||
.insertInto('test_releases')
|
||||
.values({
|
||||
test_entity_id: input.entityId,
|
||||
entity_type: input.entityType,
|
||||
entity_tmdb_id: input.entityTmdbId,
|
||||
title: input.title,
|
||||
size_bytes: input.size_bytes,
|
||||
languages: JSON.stringify(input.languages),
|
||||
|
||||
@@ -6,7 +6,8 @@ import type { PCDCache } from '../../cache.ts';
|
||||
import { writeOperation, type OperationLayer } from '../../writer.ts';
|
||||
|
||||
export interface CreateTestReleasesInput {
|
||||
entityId: number;
|
||||
entityType: 'movie' | 'series';
|
||||
entityTmdbId: number;
|
||||
title: string;
|
||||
size_bytes: number | null;
|
||||
languages: string[];
|
||||
@@ -37,14 +38,16 @@ export async function createReleases(options: CreateTestReleasesOptions) {
|
||||
};
|
||||
}
|
||||
|
||||
// Get the entity ID (all inputs should have the same entityId)
|
||||
const entityId = inputs[0].entityId;
|
||||
// Get the entity key (all inputs should have the same entity)
|
||||
const entityType = inputs[0].entityType;
|
||||
const entityTmdbId = inputs[0].entityTmdbId;
|
||||
|
||||
// Check for existing releases for this entity
|
||||
const existingReleases = await db
|
||||
.selectFrom('test_releases')
|
||||
.select(['title'])
|
||||
.where('test_entity_id', '=', entityId)
|
||||
.where('entity_type', '=', entityType)
|
||||
.where('entity_tmdb_id', '=', entityTmdbId)
|
||||
.execute();
|
||||
|
||||
const existingTitles = new Set(existingReleases.map((r) => r.title));
|
||||
@@ -69,7 +72,8 @@ export async function createReleases(options: CreateTestReleasesOptions) {
|
||||
const insertRelease = db
|
||||
.insertInto('test_releases')
|
||||
.values({
|
||||
test_entity_id: input.entityId,
|
||||
entity_type: input.entityType,
|
||||
entity_tmdb_id: input.entityTmdbId,
|
||||
title: input.title,
|
||||
size_bytes: input.size_bytes,
|
||||
languages: JSON.stringify(input.languages),
|
||||
|
||||
@@ -9,34 +9,42 @@ export interface DeleteTestEntityOptions {
|
||||
databaseId: number;
|
||||
cache: PCDCache;
|
||||
layer: OperationLayer;
|
||||
entityId: number;
|
||||
entityType: 'movie' | 'series';
|
||||
entityTmdbId: number;
|
||||
entityTitle: string; // For metadata
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a test entity and its releases by writing an operation to the specified layer
|
||||
* Uses stable composite key (type, tmdb_id) instead of auto-generated id
|
||||
*/
|
||||
export async function remove(options: DeleteTestEntityOptions) {
|
||||
const { databaseId, cache, layer, entityId } = options;
|
||||
const { databaseId, cache, layer, entityType, entityTmdbId, entityTitle } = options;
|
||||
const db = cache.kb;
|
||||
|
||||
// Delete releases first (foreign key constraint)
|
||||
// Delete releases first (uses composite FK)
|
||||
const deleteReleases = db
|
||||
.deleteFrom('test_releases')
|
||||
.where('test_entity_id', '=', entityId)
|
||||
.where('entity_type', '=', entityType)
|
||||
.where('entity_tmdb_id', '=', entityTmdbId)
|
||||
.compile();
|
||||
|
||||
// Delete the entity
|
||||
const deleteEntity = db.deleteFrom('test_entities').where('id', '=', entityId).compile();
|
||||
// Delete the entity using stable composite key
|
||||
const deleteEntity = db
|
||||
.deleteFrom('test_entities')
|
||||
.where('type', '=', entityType)
|
||||
.where('tmdb_id', '=', entityTmdbId)
|
||||
.compile();
|
||||
|
||||
const result = await writeOperation({
|
||||
databaseId,
|
||||
layer,
|
||||
description: `delete-test-entity-${entityId}`,
|
||||
description: `delete-test-entity-${entityTitle.replace(/[^a-zA-Z0-9]/g, '-').toLowerCase()}`,
|
||||
queries: [deleteReleases, deleteEntity],
|
||||
metadata: {
|
||||
operation: 'delete',
|
||||
entity: 'test_entity',
|
||||
name: `id:${entityId}`
|
||||
name: entityTitle
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -28,14 +28,13 @@ export async function list(cache: PCDCache) {
|
||||
|
||||
if (entities.length === 0) return [];
|
||||
|
||||
const entityIds = entities.map((e) => e.id);
|
||||
|
||||
// 2. Get all releases for all entities
|
||||
const allReleases = await db
|
||||
.selectFrom('test_releases')
|
||||
.select([
|
||||
'id',
|
||||
'test_entity_id',
|
||||
'entity_type',
|
||||
'entity_tmdb_id',
|
||||
'title',
|
||||
'size_bytes',
|
||||
'languages',
|
||||
@@ -44,24 +43,25 @@ export async function list(cache: PCDCache) {
|
||||
'created_at',
|
||||
'updated_at'
|
||||
])
|
||||
.where('test_entity_id', 'in', entityIds)
|
||||
.orderBy('test_entity_id')
|
||||
.orderBy('entity_type')
|
||||
.orderBy('entity_tmdb_id')
|
||||
.orderBy('title')
|
||||
.execute();
|
||||
|
||||
// Build releases map
|
||||
const releasesMap = new Map<number, typeof allReleases>();
|
||||
// Build releases map using composite key
|
||||
const releasesMap = new Map<string, typeof allReleases>();
|
||||
for (const release of allReleases) {
|
||||
if (!releasesMap.has(release.test_entity_id)) {
|
||||
releasesMap.set(release.test_entity_id, []);
|
||||
const key = `${release.entity_type}-${release.entity_tmdb_id}`;
|
||||
if (!releasesMap.has(key)) {
|
||||
releasesMap.set(key, []);
|
||||
}
|
||||
releasesMap.get(release.test_entity_id)!.push(release);
|
||||
releasesMap.get(key)!.push(release);
|
||||
}
|
||||
|
||||
// Build the final result
|
||||
return entities.map((entity) => ({
|
||||
...entity,
|
||||
releases: (releasesMap.get(entity.id) || []).map((r) => ({
|
||||
releases: (releasesMap.get(`${entity.type}-${entity.tmdb_id}`) || []).map((r) => ({
|
||||
id: r.id,
|
||||
title: r.title,
|
||||
size_bytes: r.size_bytes !== null ? Number(r.size_bytes) : null,
|
||||
|
||||
@@ -221,7 +221,8 @@ export interface TestEntitiesTable {
|
||||
|
||||
export interface TestReleasesTable {
|
||||
id: Generated<number>;
|
||||
test_entity_id: number;
|
||||
entity_type: 'movie' | 'series';
|
||||
entity_tmdb_id: number;
|
||||
title: string;
|
||||
size_bytes: number | null;
|
||||
languages: string; // JSON array
|
||||
|
||||
@@ -237,36 +237,3 @@ export function groupSonarrReleases(
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Test Release Conversion
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Shape for PCD test release creation
|
||||
*/
|
||||
export interface TestReleaseInput {
|
||||
entityId: number;
|
||||
title: string;
|
||||
size_bytes: number | null;
|
||||
languages: string[];
|
||||
indexers: string[];
|
||||
flags: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert grouped releases to test release inputs
|
||||
*/
|
||||
export function groupedReleasesToTestInputs(
|
||||
groupedReleases: GroupedRelease[],
|
||||
entityId: number
|
||||
): TestReleaseInput[] {
|
||||
return groupedReleases.map((r) => ({
|
||||
entityId,
|
||||
title: r.title,
|
||||
size_bytes: r.size,
|
||||
languages: r.languages,
|
||||
indexers: r.indexers,
|
||||
flags: r.flags
|
||||
}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user