list page pt. 2
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { desc, eq, like } from "drizzle-orm";
|
import { desc, eq, inArray, like } from "drizzle-orm";
|
||||||
import { anime, animeSongLinks, artists, groups, songs } from "$lib/db/schema";
|
import { anime, animeSongLinks, artists, groups, songs } from "$lib/db/schema";
|
||||||
import type { ClientDb } from "./index";
|
import type { ClientDb } from "./index";
|
||||||
|
|
||||||
@@ -124,6 +124,53 @@ export async function getAnimeWithSongsByAnnId(db: ClientDb, annId: number) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch songs for a list of MAL anime ids.
|
||||||
|
*
|
||||||
|
* This joins `anime` -> `anime_song_links` -> `songs` and includes artist/group name.
|
||||||
|
*
|
||||||
|
* Intended usage: MAL animelist entries give you `node.id` (MAL id); pass those ids here.
|
||||||
|
*/
|
||||||
|
export async function getSongsForMalAnimeIds(
|
||||||
|
db: ClientDb,
|
||||||
|
malAnimeIds: number[],
|
||||||
|
) {
|
||||||
|
const ids = malAnimeIds.filter((n) => Number.isFinite(n));
|
||||||
|
if (ids.length === 0) return [];
|
||||||
|
|
||||||
|
return db
|
||||||
|
.select({
|
||||||
|
annId: anime.annId,
|
||||||
|
malId: anime.malId,
|
||||||
|
animeName: anime.mainName,
|
||||||
|
year: anime.year,
|
||||||
|
seasonId: anime.seasonId,
|
||||||
|
|
||||||
|
annSongId: animeSongLinks.annSongId,
|
||||||
|
type: animeSongLinks.type,
|
||||||
|
number: animeSongLinks.number,
|
||||||
|
|
||||||
|
songName: songs.name,
|
||||||
|
fileName: songs.fileName,
|
||||||
|
|
||||||
|
artistName: artists.name,
|
||||||
|
groupName: groups.name,
|
||||||
|
})
|
||||||
|
.from(anime)
|
||||||
|
.innerJoin(animeSongLinks, eq(animeSongLinks.annId, anime.annId))
|
||||||
|
.innerJoin(songs, eq(songs.annSongId, animeSongLinks.annSongId))
|
||||||
|
.leftJoin(artists, eq(artists.songArtistId, songs.songArtistId))
|
||||||
|
.leftJoin(groups, eq(groups.songGroupId, songs.songGroupId))
|
||||||
|
.where(inArray(anime.malId, ids))
|
||||||
|
.orderBy(
|
||||||
|
desc(anime.year),
|
||||||
|
desc(anime.seasonId),
|
||||||
|
desc(anime.annId),
|
||||||
|
desc(animeSongLinks.type),
|
||||||
|
desc(animeSongLinks.number),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function clampLimit(limit: number) {
|
function clampLimit(limit: number) {
|
||||||
const n = Number(limit);
|
const n = Number(limit);
|
||||||
if (!Number.isFinite(n)) return DEFAULT_LIST_LIMIT;
|
if (!Number.isFinite(n)) return DEFAULT_LIST_LIMIT;
|
||||||
|
|||||||
@@ -1,18 +1,13 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { desc, eq, inArray } from "drizzle-orm";
|
|
||||||
import { Debounced } from "runed";
|
import { Debounced } from "runed";
|
||||||
import { useSearchParams } from "runed/kit";
|
import { useSearchParams } from "runed/kit";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import type { ClientDb } from "$lib/db/client-db";
|
|
||||||
import { ensureSeeded, getClientDb } from "$lib/db/client-db";
|
|
||||||
import {
|
import {
|
||||||
anime,
|
ensureSeeded,
|
||||||
animeSongLinks,
|
getClientDb,
|
||||||
artists,
|
getSongsForMalAnimeIds,
|
||||||
groups,
|
} from "$lib/db/client-db";
|
||||||
songs,
|
|
||||||
} from "$lib/db/schema";
|
|
||||||
import {
|
import {
|
||||||
MalAnimeListQuerySchema,
|
MalAnimeListQuerySchema,
|
||||||
MalAnimeListResponseSchema,
|
MalAnimeListResponseSchema,
|
||||||
@@ -45,7 +40,7 @@
|
|||||||
let malEntries = $state<MalEntry[]>([]);
|
let malEntries = $state<MalEntry[]>([]);
|
||||||
let malUsername = $state<string | null>(null);
|
let malUsername = $state<string | null>(null);
|
||||||
|
|
||||||
type SongRow = Awaited<ReturnType<typeof querySongsForMalAnimeIds>>[number];
|
type SongRow = Awaited<ReturnType<typeof getSongsForMalAnimeIds>>[number];
|
||||||
let songRows = $state<SongRow[]>([]);
|
let songRows = $state<SongRow[]>([]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,67 +79,6 @@
|
|||||||
return MalAnimeListResponseSchema.parse(json);
|
return MalAnimeListResponseSchema.parse(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Client-side DB query:
|
|
||||||
* Given MAL anime ids, find matching `anime` rows by `anime.malId`,
|
|
||||||
* then fetch linked songs with artist/group names.
|
|
||||||
*
|
|
||||||
* Uses inferred types from the Drizzle select shape; no separate type defs.
|
|
||||||
*/
|
|
||||||
async function querySongsForMalAnimeIds(db: ClientDb, malAnimeIds: number[]) {
|
|
||||||
const ids = malAnimeIds.filter((n) => Number.isFinite(n));
|
|
||||||
if (ids.length === 0) return [];
|
|
||||||
|
|
||||||
// 1) Resolve MAL ids -> AMQ annIds
|
|
||||||
const annRows = await db
|
|
||||||
.select({
|
|
||||||
annId: anime.annId,
|
|
||||||
malId: anime.malId,
|
|
||||||
animeName: anime.mainName,
|
|
||||||
year: anime.year,
|
|
||||||
seasonId: anime.seasonId,
|
|
||||||
})
|
|
||||||
.from(anime)
|
|
||||||
.where(inArray(anime.malId, ids));
|
|
||||||
|
|
||||||
const annIds = annRows.map((r) => r.annId);
|
|
||||||
if (annIds.length === 0) return [];
|
|
||||||
|
|
||||||
// 2) Fetch songs linked to those annIds
|
|
||||||
// Note: we keep the selection explicit for stable inferred return types.
|
|
||||||
return db
|
|
||||||
.select({
|
|
||||||
annId: animeSongLinks.annId,
|
|
||||||
annSongId: animeSongLinks.annSongId,
|
|
||||||
type: animeSongLinks.type,
|
|
||||||
number: animeSongLinks.number,
|
|
||||||
|
|
||||||
songName: songs.name,
|
|
||||||
fileName: songs.fileName,
|
|
||||||
|
|
||||||
artistName: artists.name,
|
|
||||||
groupName: groups.name,
|
|
||||||
|
|
||||||
animeName: anime.mainName,
|
|
||||||
year: anime.year,
|
|
||||||
seasonId: anime.seasonId,
|
|
||||||
malId: anime.malId,
|
|
||||||
})
|
|
||||||
.from(animeSongLinks)
|
|
||||||
.innerJoin(anime, eq(anime.annId, animeSongLinks.annId))
|
|
||||||
.innerJoin(songs, eq(songs.annSongId, animeSongLinks.annSongId))
|
|
||||||
.leftJoin(artists, eq(artists.songArtistId, songs.songArtistId))
|
|
||||||
.leftJoin(groups, eq(groups.songGroupId, songs.songGroupId))
|
|
||||||
.where(inArray(animeSongLinks.annId, annIds))
|
|
||||||
.orderBy(
|
|
||||||
desc(anime.year),
|
|
||||||
desc(anime.seasonId),
|
|
||||||
desc(anime.annId),
|
|
||||||
desc(animeSongLinks.type),
|
|
||||||
desc(animeSongLinks.number),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadAllFor(username: string) {
|
async function loadAllFor(username: string) {
|
||||||
const u = username.trim();
|
const u = username.trim();
|
||||||
if (!u) {
|
if (!u) {
|
||||||
|
|||||||
Reference in New Issue
Block a user