Work on albums view

Lots of unanswered questions, but significantly faster. Will probably need to take another look at the database and see if there's something more/different I can do, but I'm liking where this is going. Really need to figure out how the scrobbles view is going to work, and albums view is currently not entirely correct.
This commit is contained in:
mitteneer 2025-03-28 20:38:50 -04:00
parent 58e232009b
commit 7256bccc36
8 changed files with 117 additions and 147 deletions

View file

@ -113,20 +113,18 @@ pub const Scrobble = jetquery.Model(
"scrobbles",
struct {
id: i32,
albumartists_id: i32,
songsartists_id: i32,
albumsongs_id: i32,
albumartist_id: i32,
songartist_id: i32,
albumsong_id: i32,
date: jetquery.DateTime,
created_at: jetquery.DateTime,
updated_at: jetquery.DateTime,
},
.{
.relations = .{
.song = jetquery.belongsTo(.Song, .{}),
.album = jetquery.belongsTo(.Album, .{}),
//.scrobbleartists = jetquery.hasMany(.Scrobbleartist, .{}),
},
},
.{ .relations = .{
.albumartist = jetquery.belongsTo(.Albumartist, .{}),
.albumsong = jetquery.belongsTo(.Albumsong, .{}),
.songartist = jetquery.belongsTo(.Songartist, .{}),
} },
);
pub const Song = jetquery.Model(
@ -207,21 +205,3 @@ pub const Albumsong = jetquery.Model(
},
},
);
pub const Scrobbleartist = jetquery.Model(
@This(),
"Scrobbleartists",
struct {
id: i32,
scrobble_id: i32,
artist_id: i32,
created_at: jetquery.DateTime,
updated_at: jetquery.DateTime,
},
.{
.relations = .{
.scrobble = jetquery.belongsTo(.Scrobble, .{}),
.artist = jetquery.belongsTo(.Artist, .{}),
},
},
);

View file

@ -7,9 +7,9 @@ pub fn up(repo: anytype) !void {
"scrobbles",
&.{
t.primaryKey("id", .{}),
t.column("albumartists_id", .integer, .{}),
t.column("songsartists_id", .integer, .{}),
t.column("albumsongs_id", .integer, .{}),
t.column("albumartist_id", .integer, .{}),
t.column("songartist_id", .integer, .{}),
t.column("albumsong_id", .integer, .{}),
t.column("date", .datetime, .{}),
t.timestamps(.{}),
},

View file

@ -1,20 +0,0 @@
const std = @import("std");
const jetquery = @import("jetquery");
const t = jetquery.schema.table;
pub fn up(repo: anytype) !void {
try repo.createTable(
"Scrobbleartists",
&.{
t.primaryKey("id", .{}),
t.column("scrobble_id", .integer, .{}),
t.column("artist_id", .integer, .{}),
t.timestamps(.{}),
},
.{},
);
}
pub fn down(repo: anytype) !void {
try repo.dropTable("Scrobbleartists", .{});
}

View file

@ -77,37 +77,45 @@ pub fn run(allocator: std.mem.Allocator, params: *jetzig.data.Value, env: jetzig
// There are very few situations where artist_check is null
// but song_check/album is not. Also yes, the order of these
// checks is weird, I didn't put a lot of thought into it
var associative_table_flags: [3]bool = [3]bool{ true, true, true };
var associative_table_ids: [3][]const u8 = [3][]const u8{ null, null, null };
//var associative_table_flags = [3]bool{ true, true, true };
var associative_table_ids = [3]?i32{ null, null, null };
if (album_check == null) {
try env.repo.execute(album_insert);
associative_table_ids[0] = try jetzig.database.Query(.Albumartist).insert(.{ .album_id = album_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo);
associative_table_flags[0] = false;
associative_table_ids[1] = try jetzig.database.Query(.Albumsong).insert(.{ .album_id = album_id, .song_id = song_id }).returning(.{.id}).execute(env.repo);
associative_table_flags[1] = false;
const albart = try jetzig.database.Query(.Albumartist).insert(.{ .album_id = album_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo);
const albson = try jetzig.database.Query(.Albumsong).insert(.{ .album_id = album_id, .song_id = song_id }).returning(.{.id}).execute(env.repo);
if (associative_table_ids[0] == null) associative_table_ids[0] = albart.?.id;
if (associative_table_ids[1] == null) associative_table_ids[1] = albson.?.id;
}
if (artist_check == null) {
try env.repo.execute(artist_insert);
if (associative_table_flags[0]) associative_table_ids[0] = try jetzig.database.Query(.Albumartist).insert(.{ .album_id = album_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo);
associative_table_ids[2] = try jetzig.database.Query(.Songartist).insert(.{ .song_id = song_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo);
associative_table_flags[2] = false;
const albart = try jetzig.database.Query(.Albumartist).insert(.{ .album_id = album_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo);
const sonart = try jetzig.database.Query(.Songartist).insert(.{ .song_id = song_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo);
if (associative_table_ids[0] == null) associative_table_ids[0] = albart.?.id;
if (associative_table_ids[2] == null) associative_table_ids[2] = sonart.?.id;
}
if (song_check == null) {
try env.repo.execute(song_insert);
if (associative_table_flags[1]) associative_table_ids[1] = try jetzig.database.Query(.Albumsong).insert(.{ .album_id = album_id, .song_id = song_id }).returning(.{.id}).execute(env.repo);
if (associative_table_flags[2]) associative_table_ids[2] = try jetzig.database.Query(.Songartist).insert(.{ .song_id = song_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo);
const albson = try jetzig.database.Query(.Albumsong).insert(.{ .album_id = album_id, .song_id = song_id }).returning(.{.id}).execute(env.repo);
const sonart = try jetzig.database.Query(.Songartist).insert(.{ .song_id = song_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo);
if (associative_table_ids[1] == null) associative_table_ids[1] = albson.?.id;
if (associative_table_ids[2] == null) associative_table_ids[2] = sonart.?.id;
}
//if (associative_table_flags[1]) associative_table_ids[1] = (try jetzig.database.Query(.Albumsong).insert(.{ .album_id = album_id, .song_id = song_id }).returning(.{.id}).execute(env.repo)).?.id;
//if (associative_table_flags[2]) associative_table_ids[2] = (try jetzig.database.Query(.Songartist).insert(.{ .song_id = song_id, .artist_id = artist_id }).returning(.{.id}).execute(env.repo)).?.id;
if (associative_table_ids[0] == null) associative_table_ids[0] = (try jetzig.database.Query(.Albumartist).findBy(.{ .album_id = album_id, .artist_id = artist_id }).execute(env.repo)).?.id;
if (associative_table_ids[1] == null) associative_table_ids[1] = (try jetzig.database.Query(.Albumsong).findBy(.{ .album_id = album_id, .song_id = song_id }).execute(env.repo)).?.id;
if (associative_table_ids[2] == null) associative_table_ids[2] = (try jetzig.database.Query(.Songartist).findBy(.{ .song_id = song_id, .artist_id = artist_id }).execute(env.repo)).?.id;
defer {
for (0..3) |i| {
if (associative_table_ids[i]) env.repo.free(associative_table_ids[i]);
}
}
//defer {
// for (0..3) |i| {
// if (associative_table_ids[i]) |id| env.repo.free(id);
// }
//}
try jetzig.database.Query(.Scrobble).insert(.{ .albumartists_id = associative_table_ids[0], .albumsong_id = associative_table_ids[1], .songartists_id = associative_table_ids[2], .date = scrobble.date }).execute(env.repo);
try jetzig.database.Query(.Scrobble).insert(.{ .albumartist_id = associative_table_ids[0].?, .albumsong_id = associative_table_ids[1].?, .songartist_id = associative_table_ids[2].?, .date = scrobble.date }).execute(env.repo);
//defer env.repo.free(scr_id);
//try jetzig.database.Query(.Scrobbleartist).insert(.{ .scrobble_id = scr_id.?.id, .artist_id = artist_id }).execute(env.repo);
}

View file

@ -5,30 +5,28 @@ const jetquery = @import("jetzig").jetquery;
pub fn index(request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object);
var albums_view = try root.put("albums", .array);
const albums = try jetzig.database.Query(.Album)
.select(.{ .id, .name })
.include(.albumartists, .{ .select = .{.artist_id} })
const albums = try jetzig.database.Query(.Albumartist)
.select(.{.id})
.include(.album, .{ .select = .{ .id, .name } })
.include(.artist, .{ .select = .{ .id, .name } })
.include(.scrobbles, .{ .select = .{.id} })
.orderBy(.{ .name = .asc })
//.groupBy(.{ .album = .{.id} })
.orderBy(.{ .album = .{ .name = .asc } })
.all(request.repo);
//const albums = try request.repo.all(query);
for (albums) |album| {
//var buf: [11]u8 = undefined;
//const id_string: []const u8 = try std.fmt.bufPrint(&buf, "{}", .{album.album.id});
var album_view = try albums_view.append(.object);
var artist_infos = try album_view.put("artist_info", .array);
for (album.albumartists) |artist| {
var artist_info = try artist_infos.append(.object);
const artist_data = try jetzig.database.Query(.Artist)
.find(artist.artist_id)
.select(.{ .id, .name })
.execute(request.repo);
try artist_info.put("name", artist_data.?.name);
try artist_info.put("id", artist_data.?.id);
}
// TODO: Come back to this when multiple artists are supported
var artist_infos = album_view.put("artist_info", .array) catch continue;
var artist_info = try artist_infos.append(.object);
try artist_info.put("name", album.artist.name);
try artist_info.put("id", album.artist.id);
try album_view.put("name", album.name);
try album_view.put("url", album.id);
try album_view.put("name", album.album.name);
try album_view.put("url", album.album.id);
try album_view.put("scrobbles", (album.scrobbles).len);
}
return request.render(.ok);
@ -45,19 +43,20 @@ pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
const query = jetzig.database.Query(.Albumsong)
.select(.{.id})
.include(.song, .{ .select = .{ .name, .id } })
.include(.scrobbles, .{ .select = .{.id} })
.join(.inner, .album)
.where(.{ .album = .{ .id = id } });
const songs = try request.repo.all(query);
for (songs) |song| {
const scrobbles = try jetzig.database.Query(.Scrobble)
.where(.{ .song_id = song.song.id })
.count()
.execute(request.repo);
//const scrobbles = try jetzig.database.Query(.Scrobble)
// .where(.{ .song_id = song.song.id })
// .count()
// .execute(request.repo);
var song_view = try songs_view.append(.object);
try song_view.put("name", song.song.name);
try song_view.put("url", song.song.id);
try song_view.put("scrobbles", scrobbles);
try song_view.put("scrobbles", (song.scrobbles).len);
}
return request.render(.ok);
}

View file

@ -5,16 +5,17 @@ const jetquery = @import("jetzig").jetquery;
pub fn index(request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object);
var artists_view = try root.put("artists", .array);
const artists = try jetzig.database.Query(.Artist)
.select(.{ .id, .name })
.include(.scrobbleartists, .{ .select = .{.id} })
.orderBy(.{ .name = .asc })
const artists = try jetzig.database.Query(.Songartist)
//.include(.song, .{ .select = .{ .id, .name } })
.include(.artist, .{ .select = .{ .id, .name } })
.include(.scrobbles, .{ .select = .{.id} })
.orderBy(.{ .artist = .{ .name = .asc } })
.all(request.repo);
for (artists) |artist| {
var artist_view = try artists_view.append(.object);
try artist_view.put("name", artist.name);
try artist_view.put("url", artist.id);
try artist_view.put("scrobbles", (artist.scrobbleartists).len);
try artist_view.put("name", artist.artist.name);
try artist_view.put("url", artist.artist.id);
try artist_view.put("scrobbles", (artist.scrobbles).len);
}
return request.render(.ok);
@ -31,19 +32,20 @@ pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
const query = jetzig.database.Query(.Albumartist)
.select(.{.id})
.include(.album, .{ .select = .{ .name, .id } })
.include(.scrobbles, .{ .select = .{.id} })
.join(.inner, .artist)
.where(.{ .artist = .{ .id = id } });
const albums = try request.repo.all(query);
for (albums) |album| {
const scrobbles = try jetzig.database.Query(.Scrobble)
.where(.{ .album_id = album.album.id })
.count()
.execute(request.repo);
//const scrobbles = try jetzig.database.Query(.Scrobble)
// .where(.{ .album_id = album.album.id })
// .count()
// .execute(request.repo);
var album_view = try albums_view.append(.object);
try album_view.put("name", album.album.name);
try album_view.put("url", album.album.id);
try album_view.put("scrobbles", scrobbles);
try album_view.put("scrobbles", (album.scrobbles).len);
}
return request.render(.ok);
}

View file

@ -2,35 +2,38 @@ const std = @import("std");
const jetzig = @import("jetzig");
pub fn index(request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object);
var scrobbles_view = try root.put("scrobbles", .array);
const query = jetzig.database.Query(.Scrobble)
.select(.{ .id, .date })
.include(.song, .{ .select = .{ .id, .name } })
.include(.album, .{ .select = .{ .id, .name } })
.include(.scrobbleartists, .{ .select = .{.artist_id} })
.orderBy(.{ .date = .desc });
const scrobbles = try request.repo.all(query);
for (scrobbles) |scrobble| {
var scrobble_view = try scrobbles_view.append(.object);
//var root = try request.data(.object);
//var scrobbles_view = try root.put("scrobbles", .array);
//const scrobbles = try jetzig.database.Query(.Songartist)
// .select(.{.id})
// .include(.song, .{ .select = .{ .id, .name } })
// .include(.artist, .{ .select = .{ .id, .name } })
// .include(.scrobbles, .{ .select = .{ .id, .date } })
// .groupBy(.{ .song_id, .artist_id })
// .orderBy(.{ .scrobbles = .{ .date = .desc } })
// .all(request.repo);
//for (scrobbles) |scrobble| {
// var buf: [11]u8 = undefined;
// const id_string:[]const u8 = try std.fmt.bufPrint(&buf, "{}", .{scrobble.})
// var scrobble_view = try scrobbles_view.append(.object);
var artist_infos = try scrobble_view.put("artist_info", .array);
for (scrobble.scrobbleartists) |artist| {
var artist_info = try artist_infos.append(.object);
const artist_data = try jetzig.database.Query(.Artist)
.find(artist.artist_id)
.select(.{ .id, .name })
.execute(request.repo);
try artist_info.put("name", artist_data.?.name);
try artist_info.put("id", artist_data.?.id);
}
// var artist_infos = try scrobble_view.put("artist_info", .array);
// for (scrobble.scrobbleartists) |artist| {
// var artist_info = try artist_infos.append(.object);
// const artist_data = try jetzig.database.Query(.Artist)
// .find(artist.artist_id)
// .select(.{ .id, .name })
// .execute(request.repo);
// try artist_info.put("name", artist_data.?.name);
// try artist_info.put("id", artist_data.?.id);
// }
try scrobble_view.put("song_name", scrobble.song.name);
try scrobble_view.put("song_id", scrobble.song.id);
try scrobble_view.put("album_name", scrobble.album.name);
try scrobble_view.put("album_id", scrobble.album.id);
try scrobble_view.put("date", scrobble.date);
}
// try scrobble_view.put("song_name", scrobble.song.name);
// try scrobble_view.put("song_id", scrobble.song.id);
// try scrobble_view.put("album_name", scrobble.album.name);
// try scrobble_view.put("album_id", scrobble.album.id);
// try scrobble_view.put("date", scrobble.date);
//}
return request.render(.ok);
}

View file

@ -3,29 +3,27 @@ const jetzig = @import("jetzig");
pub fn index(request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object);
var songs_view = try root.put("songs", .array);
const songs = try jetzig.database.Query(.Song)
.select(.{ .id, .name })
.include(.songartists, .{ .select = .{.artist_id} })
//var songs_view = try root.put("songs", .array);
const songs = try jetzig.database.Query(.Songartist)
.select(.{.id})
.include(.song, .{ .select = .{ .id, .name } })
.include(.artist, .{ .select = .{ .id, .name } })
.include(.scrobbles, .{ .select = .{.id} })
.orderBy(.{ .name = .asc })
.orderBy(.{ .song = .{ .name = .asc } })
.all(request.repo);
for (songs) |song| {
var song_view = try songs_view.append(.object);
var buf: [11]u8 = undefined;
const id_string: []const u8 = try std.fmt.bufPrint(&buf, "{}", .{song.song.id});
var song_view = try root.put(id_string, .object);
var artist_infos = try song_view.put("artist_info", .array);
for (song.songartists) |artist| {
var artist_info = try artist_infos.append(.object);
const artist_data = try jetzig.database.Query(.Artist)
.find(artist.artist_id)
.select(.{ .id, .name })
.execute(request.repo);
try artist_info.put("name", artist_data.?.name);
try artist_info.put("id", artist_data.?.id);
}
try song_view.put("name", song.name);
try song_view.put("url", song.id);
var artist_infos = song_view.put("artist_info", .array) catch continue;
var artist_info = try artist_infos.append(.object);
try artist_info.put("name", song.artist.name);
try artist_info.put("id", song.artist.id);
try song_view.put("name", song.song.name);
try song_view.put("url", song.song.id);
try song_view.put("scrobbles", (song.scrobbles).len);
}
return request.render(.ok);