From 62590fee374fab21c36976724d014a5a1b15f787 Mon Sep 17 00:00:00 2001 From: mitteneer Date: Thu, 29 May 2025 19:39:51 -0400 Subject: [PATCH] Made queries.zig look significantly nicer There's a little bit of weird stuff happening, but holy cannoli, that's so much easier to maintain and parse --- src/app/views/albums.zig | 12 +- src/app/views/artists.zig | 14 +- .../views/partials/_firstlast_listens.zmpl | 4 +- src/app/views/partials/_timescale.zmpl | 2 +- src/app/views/scrobbles.zig | 2 +- src/app/views/songs.zig | 14 +- src/queries.zig | 179 ++++++------------ 7 files changed, 87 insertions(+), 140 deletions(-) diff --git a/src/app/views/albums.zig b/src/app/views/albums.zig index af72456..713e6d6 100644 --- a/src/app/views/albums.zig +++ b/src/app/views/albums.zig @@ -8,7 +8,7 @@ const queries = @import("../../queries.zig"); pub fn index(request: *jetzig.Request) !jetzig.View { var root = try request.data(.object); - const albums = try queries.entityQueryResult(request, queries.generateQuery(.album, .entities), .{}, .array); + const albums = try queries.entityQueryResult(request, queries.loadQuery(.album, .entities), .{}); try root.put("albums", albums); return request.render(.ok); @@ -17,16 +17,16 @@ pub fn index(request: *jetzig.Request) !jetzig.View { pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View { var root = try request.data(.object); - const album = try queries.entityQueryResult(request, queries.generateQuery(.album, .entity_info), .{id}, .object); - try root.put("album", album.get("entity_info")); + const album = try queries.entityQueryResult(request, queries.loadQuery(.album, .entity_info), .{id}); + try root.put("album", album); - const songs = try queries.entityQueryResult(request, queries.generateQuery(.album, .entity_items), .{id}, .array); + const songs = try queries.entityQueryResult(request, queries.loadQuery(.album, .entity_items), .{id}); try root.put("songs", songs); - const firstlast = try queries.entityQueryResult(request, queries.generateQuery(.album, .firstlast), .{id}, .array); + const firstlast = try queries.entityQueryResult(request, queries.loadQuery(.album, .firstlast), .{id}); try root.put("firstlast", firstlast); - const timescale = try queries.entityQueryResult(request, queries.generateQuery(.album, .timescale), .{id}, .array); + const timescale = try queries.entityQueryResult(request, queries.loadQuery(.album, .timescale), .{id}); try root.put("yearly", timescale); return request.render(.ok); diff --git a/src/app/views/artists.zig b/src/app/views/artists.zig index 37ca155..1f7ff85 100644 --- a/src/app/views/artists.zig +++ b/src/app/views/artists.zig @@ -8,7 +8,7 @@ const queries = @import("../../queries.zig"); pub fn index(request: *jetzig.Request) !jetzig.View { var root = try request.data(.object); - const artists = try queries.entityQueryResult(request, queries.generateQuery(.artist, .entities), .{}, .array); + const artists = try queries.entityQueryResult(request, queries.loadQuery(.artist, .entities), .{}); try root.put("artists", artists); @@ -18,19 +18,19 @@ pub fn index(request: *jetzig.Request) !jetzig.View { pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View { var root = try request.data(.object); - const artist = try queries.entityQueryResult(request, queries.generateQuery(.artist, .entity_info), .{id}, .object); - try root.put("artist", artist.get("entity_info")); + const artist = try queries.entityQueryResult(request, queries.loadQuery(.artist, .entity_info), .{id}); + try root.put("artist", artist); - const albums = try queries.entityQueryResult(request, queries.generateQuery(.artist, .entity_items), .{id}, .array); + const albums = try queries.entityQueryResult(request, queries.loadQuery(.artist, .entity_items), .{id}); try root.put("albums", albums); - const appears = try queries.entityQueryResult(request, queries.generateQuery(.artist, .appears), .{id}, .array); + const appears = try queries.entityQueryResult(request, queries.loadQuery(.artist, .appears), .{id}); try root.put("appears", appears); - const firstlast = try queries.entityQueryResult(request, queries.generateQuery(.artist, .firstlast), .{id}, .array); + const firstlast = try queries.entityQueryResult(request, queries.loadQuery(.artist, .firstlast), .{id}); try root.put("firstlast", firstlast); - const timescale = try queries.entityQueryResult(request, queries.generateQuery(.artist, .timescale), .{id}, .array); + const timescale = try queries.entityQueryResult(request, queries.loadQuery(.artist, .timescale), .{id}); try root.put("yearly", timescale); return request.render(.ok); diff --git a/src/app/views/partials/_firstlast_listens.zmpl b/src/app/views/partials/_firstlast_listens.zmpl index ed74361..a21114b 100644 --- a/src/app/views/partials/_firstlast_listens.zmpl +++ b/src/app/views/partials/_firstlast_listens.zmpl @@ -7,7 +7,7 @@
{{scrobbles}} scrobbles ({{rank}} place)
-First listen: {{songs[0].name}} ({{songs[0].date}}) +First listen: {{songs[0].song.name}} ({{songs[0].date}})
-Most recent listen: {{songs[1].name}} ({{songs[1].date}}) +Most recent listen: {{songs[1].song.name}} ({{songs[1].date}})
\ No newline at end of file diff --git a/src/app/views/partials/_timescale.zmpl b/src/app/views/partials/_timescale.zmpl index fdec7a1..9937ec6 100644 --- a/src/app/views/partials/_timescale.zmpl +++ b/src/app/views/partials/_timescale.zmpl @@ -10,7 +10,7 @@ @for (range) |itm| { - {{itm.year}}: + {{itm.date}}: {{itm.scrobbles}} } diff --git a/src/app/views/scrobbles.zig b/src/app/views/scrobbles.zig index e61df4d..754a7c8 100644 --- a/src/app/views/scrobbles.zig +++ b/src/app/views/scrobbles.zig @@ -5,7 +5,7 @@ const queries = @import("../../queries.zig"); pub fn index(request: *jetzig.Request) !jetzig.View { var root = try request.data(.object); - const scrobbles = try queries.entityQueryResult(request, queries.generateQuery(.scrobble, .entities), .{}, .array); + const scrobbles = try queries.entityQueryResult(request, queries.loadQuery(.scrobble, .entities), .{}); try root.put("scrobbles", scrobbles); return request.render(.ok); diff --git a/src/app/views/songs.zig b/src/app/views/songs.zig index 3143f01..b24dbf5 100644 --- a/src/app/views/songs.zig +++ b/src/app/views/songs.zig @@ -5,7 +5,7 @@ const queries = @import("../../queries.zig"); pub fn index(request: *jetzig.Request) !jetzig.View { var root = try request.data(.object); - const songs = try queries.entityQueryResult(request, queries.generateQuery(.song, .entities), .{}, .array); + const songs = try queries.entityQueryResult(request, queries.loadQuery(.song, .entities), .{}); try root.put("songs", songs); return request.render(.ok); @@ -14,19 +14,19 @@ pub fn index(request: *jetzig.Request) !jetzig.View { pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View { var root = try request.data(.object); - const song = try queries.entityQueryResult(request, queries.generateQuery(.song, .entity_info), .{id}, .object); - try root.put("song", song.get("entity_info")); + const song = try queries.entityQueryResult(request, queries.loadQuery(.song, .entity_info), .{id}); + try root.put("song", song); - const scrobbles = try queries.entityQueryResult(request, queries.generateQuery(.song, .entity_items), .{id}, .array); + const scrobbles = try queries.entityQueryResult(request, queries.loadQuery(.song, .entity_items), .{id}); try root.put("scrobbles", scrobbles); - const appears = try queries.entityQueryResult(request, queries.generateQuery(.song, .appears), .{id}, .array); + const appears = try queries.entityQueryResult(request, queries.loadQuery(.song, .appears), .{id}); try root.put("appears", appears); - const firstlast = try queries.entityQueryResult(request, queries.generateQuery(.song, .firstlast), .{id}, .array); + const firstlast = try queries.entityQueryResult(request, queries.loadQuery(.song, .firstlast), .{id}); try root.put("firstlast", firstlast); - const timescale = try queries.entityQueryResult(request, queries.generateQuery(.song, .timescale), .{id}, .array); + const timescale = try queries.entityQueryResult(request, queries.loadQuery(.song, .timescale), .{id}); try root.put("yearly", timescale); return request.render(.ok); } diff --git a/src/queries.zig b/src/queries.zig index 061b5b3..0411022 100644 --- a/src/queries.zig +++ b/src/queries.zig @@ -4,135 +4,82 @@ const TableRow = @import("types.zig").TableRow; const HyperlinkData = @import("types.zig").HyperlinkData; const std = @import("std"); -pub fn entityQueryResult(request: *jetzig.Request, query: GeneratedQuery, args: anytype, root_type: enum { object, array }) !*jetzig.Data.Value { - var result = try request.repo.executeSql(query.query, args); +pub fn entityQueryResult(request: *jetzig.Request, query: GeneratedQuery, args: anytype) !*jetzig.Data.Value { + //var result = try request.repo.executeSql(query.query, args); + // + var result = try request.repo.connection.?.postgresql.connection.queryOpts(query.query, args, .{ .allocator = request.allocator, .column_names = true }); defer result.deinit(); var Data = jetzig.Data.init(request.allocator); - var out: *jetzig.Data.Value = switch (root_type) { - .array => try Data.array(), - .object => try Data.object(), - }; - var artist_list = if (query.ResultType == EntitiesAlbumResult or query.ResultType == EntitiesArtistResult or query.ResultType == EntitiesScrobbleResult or query.ResultType == EntitiesSongResult) - std.ArrayList(HyperlinkData).init(request.allocator); + var artist_list = std.ArrayList(HyperlinkData).init(request.allocator); - blk: while (try result.postgresql.result.next()) |entity_row| { - switch (query.ResultType) { - FirstlastResult, TimescaleResult, EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult, EntityItemsResult, AppearsResult, EntityInfoResult, EntityItemsSongResult => |T| { - const entity = try entity_row.to(T, .{ .dupe = true, .allocator = request.allocator }); - const item: ?TableRow = switch (query.ResultType) { - EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult => switch (query.entity) { - .artist => TableRow{ .artist = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles }, - .scrobble, .song, .album => album_entities: { - const last_artist = artist_list.getLastOrNull(); - try artist_list.append(.{ .name = entity.artist_name, .id = entity.artist_id }); - if (last_artist) |la| { - if (la.id == entity.artist_id) continue :blk; - } - break :album_entities switch (query.entity) { - .scrobble => TableRow{ .song = .{ .name = entity.song_name, .id = entity.song_id }, .album = .{ .name = entity.album_name, .id = entity.album_id }, .artistlist = try artist_list.toOwnedSlice(), .date = entity.date }, - .song => TableRow{ .song = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles }, - .album => TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles }, - else => unreachable, - }; - }, - }, - EntityItemsResult, EntityItemsSongResult => switch (query.entity) { - .song => TableRow{ .song = .{ .name = entity.song_name, .id = entity.song_id }, .album = .{ .name = entity.album_name, .id = entity.album_id }, .date = entity.date }, - .artist => TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles }, - .album => TableRow{ .song = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles }, - else => unreachable, - }, - AppearsResult => switch (query.entity) { - .song, .artist => TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles }, - .album, .scrobble => unreachable, - }, - else => null, - }; - - if (item) |itm| { - switch (root_type) { - .array => try out.append(itm), - .object => switch (query.query_type) { - inline else => |qt| try out.put(@tagName(qt), itm), - }, - } - } else { - switch (root_type) { - .array => try out.append(entity), - .object => switch (query.query_type) { - inline else => |qt| try out.put(@tagName(qt), entity), - }, - } - } - }, - else => unreachable, - } + if (query.query_type == .entity_info) { + var out: *jetzig.Data.Value = try Data.object(); + const entity = try (try result.next()).?.to(struct { name: []const u8, id: i32, scrobbles: i64, rank: []const u8 }, .{ .dupe = true, .allocator = request.allocator }); + const entity_struct = .{ .name = entity.name, .id = entity.id, .scrobbles = entity.scrobbles, .rank = entity.rank }; + try out.put("entity_info", entity_struct); + try result.drain(); + return out.get("entity_info").?; } - if (root_type == .object) {} + + var out: *jetzig.Data.Value = try Data.array(); + var mapper = result.mapper(UnifiedResult, .{ .dupe = true, .allocator = request.allocator }); + + blk: while (try mapper.next()) |entity| { + if (entity.artist_id) |_| { + const last_artist = artist_list.getLastOrNull(); + try artist_list.append(.{ .name = entity.artist_name.?, .id = entity.artist_id.? }); + if (last_artist) |la| { + if (la.id == entity.artist_id) continue :blk; + } + } + + try out.append(TableRow{ + .artist = if (entity.artist_id) |_| .{ .id = entity.artist_id.?, .name = entity.artist_name.? } else null, + .album = if (entity.album_id) |_| .{ .id = entity.album_id.?, .name = entity.album_name.? } else null, + .song = if (entity.song_id) |_| .{ .id = entity.song_id.?, .name = entity.song_name.? } else null, + .artistlist = if (artist_list.getLastOrNull()) |_| try artist_list.toOwnedSlice() else null, + .scrobbles = if (entity.scrobbles) |scrobbles| scrobbles else null, + .date = if (entity.date) |date| date else null, + }); + } + return out; } +const EntityType = enum { scrobble, song, album, artist }; +const QueryTypeEnum = enum { firstlast, timescale, entities, entity_items, appears, entity_info, datestreak }; + const GeneratedQuery = struct { entity: EntityType, query_type: QueryTypeEnum, - ResultType: type, query: []const u8, }; -const EntityType = enum { scrobble, song, album, artist }; -const QueryTypeEnum = enum { firstlast, timescale, entities, entity_items, appears, entity_info }; -const FirstlastResult = struct { name: []const u8, id: i32, date: []const u8 }; -const TimescaleResult = struct { year: []const u8, scrobbles: i64 }; -const EntitiesArtistResult = struct { name: []const u8, id: i32, scrobbles: i64 }; -const EntitiesAlbumResult = struct { name: []const u8, id: i32, artist_name: []const u8, artist_id: i32, scrobbles: i64 }; -const EntitiesSongResult = struct { name: []const u8, id: i32, artist_name: []const u8, artist_id: i32, scrobbles: i64 }; -const EntitiesScrobbleResult = struct { song_name: []const u8, song_id: i32, album_name: []const u8, album_id: i32, artist_name: []const u8, artist_id: i32, date: []const u8 }; -const EntityItemsResult = struct { name: []const u8, id: i32, scrobbles: i64 }; -const AppearsResult = struct { name: []const u8, id: i32, scrobbles: i64 }; -const EntityInfoResult = struct { name: []const u8, id: i32, scrobbles: i64, rank: []const u8 }; -const EntityItemsSongResult = struct { song_name: []const u8, song_id: i32, album_name: []const u8, album_id: i32, date: []const u8 }; const UnifiedResult = struct { album_name: ?[]const u8 = null, album_id: ?i32 = null, song_name: ?[]const u8 = null, song_id: ?i32 = null, - artist_names: ?[]const []const u8 = null, - artist_ids: ?[]i32 = null, + artist_name: ?[]const u8 = null, + artist_id: ?i32 = null, scrobbles: ?i64 = null, date: ?[]const u8 = null, }; -pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQuery { +pub fn loadQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQuery { return GeneratedQuery{ .entity = entity, .query_type = query_type, - .ResultType = switch (query_type) { - .firstlast => FirstlastResult, - .timescale => TimescaleResult, - .entities => switch (entity) { - .scrobble => EntitiesScrobbleResult, - .song => EntitiesSongResult, - .album => EntitiesAlbumResult, - .artist => EntitiesArtistResult, - }, - .entity_items => switch (entity) { - .scrobble => unreachable, - .song => EntityItemsSongResult, - else => EntityItemsResult, - }, - .appears => AppearsResult, - .entity_info => EntityInfoResult, - }, .query = switch (query_type) { .firstlast => //.ResultType = FirstlastResult, switch (entity) { .scrobble => unreachable, .song => - \\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime,'YYYY-MM-DD HH24:MI:SS') AS date + \\(SELECT songs.name AS song_name, songs.id AS song_id, TO_CHAR(scrobbles.datetime,'YYYY-MM-DD HH24:MI:SS') AS date \\FROM albumsongs \\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong @@ -142,7 +89,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue \\ \\UNION ALL \\ - \\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date + \\(SELECT songs.name AS song_name, songs.id AS song_id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date \\FROM albumsongs \\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong @@ -152,7 +99,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue , .album => - \\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date + \\(SELECT songs.name AS song_name, songs.id AS song_id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date \\FROM albumsongs \\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong @@ -163,7 +110,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue \\ \\UNION ALL \\ - \\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date + \\(SELECT songs.name AS song_name, songs.id AS song_id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date \\FROM albumsongs \\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong @@ -174,7 +121,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue , .artist => - \\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date + \\(SELECT songs.name AS song_name, songs.id AS song_id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date \\FROM albumsongs \\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong @@ -185,7 +132,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue \\ \\UNION ALL \\ - \\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date + \\(SELECT songs.name AS song_name, songs.id AS song_id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date \\FROM albumsongs \\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong @@ -201,34 +148,34 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue switch (entity) { .scrobble => unreachable, .song => - \\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS year, COUNT(*) as scrobbles + \\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS date, COUNT(*) as scrobbles \\FROM scrobbles \\INNER JOIN albumsongs ON albumsongs.id = scrobbles.albumsong \\INNER JOIN songs ON songs.id = albumsongs.song_id \\WHERE songs.id = $1 - \\GROUP BY year - \\ORDER BY year ASC; + \\GROUP BY date + \\ORDER BY date ASC; , .album => - \\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS year, COUNT(*) as scrobbles + \\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS date, COUNT(*) as scrobbles \\FROM scrobbles \\INNER JOIN albumsongs ON albumsongs.id = scrobbles.albumsong \\INNER JOIN albums ON albums.id = albumsongs.album_id \\WHERE albums.id = $1 - \\GROUP BY year - \\ORDER BY year ASC; + \\GROUP BY date + \\ORDER BY date ASC; , .artist => - \\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS year, COUNT(*) as scrobbles + \\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS date, COUNT(*) as scrobbles \\FROM scrobbles \\INNER JOIN albumsongs ON albumsongs.id = scrobbles.albumsong \\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id \\INNER JOIN artists ON artists.id = albumsongsartists.artist_id \\WHERE artists.id = $1 - \\GROUP BY year - \\ORDER BY year ASC; + \\GROUP BY date + \\ORDER BY date ASC; , }, @@ -246,7 +193,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue \\ORDER BY scrobbles.datetime ASC , .song => - \\SELECT songs.name, songs.id, artists.name, artists.id, COUNT(scrobbles) AS scrobbles + \\SELECT songs.name AS song_name, songs.id AS song_id, artists.name AS artist_name, artists.id AS artist_id, COUNT(scrobbles) AS scrobbles \\FROM albumsongs \\INNER JOIN songs ON albumsongs.song_id = songs.id \\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id @@ -256,7 +203,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue \\ORDER BY scrobbles DESC, songs.name ASC , .album => - \\SELECT albums.name, albums.id, artists.name, artists.id, COUNT(scrobbles) AS scrobbles + \\SELECT albums.name AS album_name, albums.id AS album_id, artists.name AS artist_name, artists.id AS artist_id, COUNT(scrobbles) AS scrobbles \\FROM albumsongs \\INNER JOIN albums ON albumsongs.album_id = albums.id \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong @@ -266,7 +213,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue \\ORDER BY scrobbles DESC , .artist => - \\SELECT artists.name AS name, artists.id AS id, COUNT(scrobbles) AS scrobbles + \\SELECT artists.name AS artist_name, artists.id AS artist_id, COUNT(scrobbles) AS scrobbles \\FROM albumsongsartists \\INNER JOIN artists ON albumsongsartists.artist_id = artists.id \\INNER JOIN albumsongs ON albumsongsartists.albumsong_id = albumsongs.id @@ -312,7 +259,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue switch (entity) { .scrobble => unreachable, .song => - \\SELECT songs.name, songs.id, albums.name, albums.id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date + \\SELECT songs.name AS song_name, songs.id AS song_id, albums.name AS album_name, albums.id AS album_id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date \\FROM albumsongs \\INNER JOIN albums ON albums.id = albumsongs.album_id \\INNER JOIN songs ON songs.id = albumsongs.song_id @@ -321,7 +268,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue \\ORDER BY date ASC , .album => - \\SELECT songs.name, songs.id, COUNT(scrobbles) AS scrobbles + \\SELECT songs.name AS song_name, songs.id AS song_id, COUNT(scrobbles) AS scrobbles \\FROM albumsongs \\INNER JOIN songs ON albumsongs.song_id = songs.id \\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id @@ -330,7 +277,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue \\ORDER BY scrobbles DESC , .artist => - \\SELECT albums.name AS name, albums.id AS id, COUNT(scrobbles) AS scrobbles + \\SELECT albums.name AS album_name, albums.id AS album_id, COUNT(scrobbles) AS scrobbles \\FROM artistalbums \\INNER JOIN albums ON albums.id = artistalbums.album_id \\INNER JOIN albumsongs ON albumsongs.album_id = albums.id @@ -378,7 +325,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue .datestreak => switch (entity) { .song => - \\SELECT songs.name, albums.name, streak.maxseq, streak.ds, streak.de FROM (SELECT albumsong, MAX(numdays) AS maxseq, ds, de + \\SELECT songs.name AS song_name, albums.name AS album_name, streak.maxseq AS intval, FORMAT('%s - %s, streak.ds, streak.de) AS date FROM (SELECT albumsong, MAX(numdays) AS maxseq, ds, de \\FROM (SELECT albumsong, grp, MIN(datetime::date) AS ds, MAX(datetime::date) AS de, \\COUNT(DISTINCT datetime::date) AS numdays \\FROM (SELECT scrobbles.*,