Compare commits

..

No commits in common. "d638fa66c550e79ccd04101e093b06b5d56970a2" and "7f3778e82f74627bfe992fd03193acec06adf9ce" have entirely different histories.

6 changed files with 183 additions and 224 deletions

View file

@ -17,8 +17,8 @@
// internet connectivity. // internet connectivity.
.dependencies = .{ .dependencies = .{
.jetzig = .{ .jetzig = .{
.url = "https://github.com/jetzig-framework/jetzig/archive/695664bc10e6e73389ee2fe7fbcaedc27fa8adc9.tar.gz", .url = "https://github.com/jetzig-framework/jetzig/archive/7be1d137fcab5c422e05f12092f6e04a02900d6f.tar.gz",
.hash = "jetzig-0.0.0-IpAgLSFeDwBEhfEaDBo0JqhRbvQA3ScbWjssBqhJHFmb", .hash = "jetzig-0.0.0-IpAgLURbDwB1NlywUH7lnQ3zptNvSQWVosaA1k7l1cNz",
}, },
.zeit = .{ .zeit = .{
.url = "https://github.com/rockorager/zeit/archive/refs/tags/v0.6.0.tar.gz", .url = "https://github.com/rockorager/zeit/archive/refs/tags/v0.6.0.tar.gz",

View file

@ -1,12 +1,56 @@
const std = @import("std"); const std = @import("std");
const jetzig = @import("jetzig"); const jetzig = @import("jetzig");
const queries = @import("../../queries.zig"); const zeit = @import("zeit");
const TableRow = @import("../../types.zig").TableRow;
const HyperlinkData = @import("../../types.zig").HyperlinkData;
const Utils = @import("../../date_fmt.zig");
pub fn index(request: *jetzig.Request) !jetzig.View { pub fn index(request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object); var root = try request.data(.object);
var scrobbles_view = try root.put("scrobbles", .array);
const scrobbles = try queries.entityQueryResult(request, queries.generateQuery(.scrobble, .entities), .{}, .array); const query =
try root.put("scrobbles", scrobbles); \\SELECT songs.name, songs.id, albums.name, albums.id, artists.name, artists.id, scrobbles.id, scrobbles.datetime
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\INNER JOIN artists ON artists.id = albumsongsartists.artist_id
\\ORDER BY scrobbles.datetime ASC
;
var scrobbles_jq_result = try request.repo.executeSql(query, .{});
defer scrobbles_jq_result.deinit();
const Scrobble = struct { song_name: []const u8, song_id: i32, album_name: []const u8, album_id: i32, artist_name: []const u8, artist_id: i32, s_id: i32, date: i64 };
var prev_s_id: ?i32 = null;
var row: ?TableRow = null;
var artistlist = std.ArrayList(HyperlinkData).init(request.allocator);
blk: while (try scrobbles_jq_result.postgresql.result.next()) |scrobble_row| {
const scrobble = try scrobble_row.to(Scrobble, .{ .dupe = true, .allocator = request.allocator });
if (scrobble.s_id == prev_s_id) {
try artistlist.append(.{ .name = scrobble.artist_name, .id = scrobble.artist_id });
continue :blk;
} else {
const date = try Utils.dateFmt(request.allocator, scrobble.date);
try artistlist.append(.{ .name = scrobble.artist_name, .id = scrobble.artist_id });
row = TableRow{
.song = .{ .name = scrobble.song_name, .id = scrobble.song_id },
.album = .{ .name = scrobble.album_name, .id = scrobble.album_id },
.artistlist = try artistlist.toOwnedSlice(),
.date = date,
};
try scrobbles_view.append(row);
}
prev_s_id = scrobble.s_id;
}
return request.render(.ok); return request.render(.ok);
} }

View file

@ -12,21 +12,6 @@ pub fn index(request: *jetzig.Request) !jetzig.View {
} }
pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View { pub fn get(id: []const u8, request: *jetzig.Request) !jetzig.View {
var root = try request.data(.object); _ = id;
const song = try queries.entityQueryResult(request, queries.generateQuery(.song, .entity_info), .{id}, .object);
try root.put("song", song.get("entity_info"));
const scrobbles = try queries.entityQueryResult(request, queries.generateQuery(.song, .entity_items), .{id}, .array);
try root.put("scrobbles", scrobbles);
const appears = try queries.entityQueryResult(request, queries.generateQuery(.song, .appears), .{id}, .array);
try root.put("appears", appears);
const firstlast = try queries.entityQueryResult(request, queries.generateQuery(.song, .firstlast), .{id}, .array);
try root.put("firstlast", firstlast);
const timescale = try queries.entityQueryResult(request, queries.generateQuery(.song, .timescale), .{id}, .array);
try root.put("yearly", timescale);
return request.render(.ok); return request.render(.ok);
} }

View file

@ -1,19 +1,3 @@
@zig { <div>
const ColumnChoices = []const enum{song, album, artist, artistlist, scrobbles, date}; <span>Content goes here</span>
const columns: ColumnChoices = &.{.song, .artistlist, .album, .date}; </div>
}
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
@partial partials/header
<h1>{{.song}}</h1>
@partial partials/firstlast_listens(scrobbles: .song.scrobbles, rank: .song.rank, firstlast: .firstlast)
<h3>Yearly Performance</h3>
@partial partials/timescale(range: .yearly)
<h2>Scrobbles</h2>
@partial partials/newtable(T: ColumnChoices, table_data: .scrobbles, columns: columns)
</body>
</html>

View file

@ -81,46 +81,23 @@ pub fn post(request: *jetzig.Request) !jetzig.View {
// Not sure if I should be proud or feel sick // Not sure if I should be proud or feel sick
switch (imported_scrobbles) { switch (imported_scrobbles) {
.LastFMStats => |scrobbles| { inline else => |scrobbles| {
appends: for (scrobbles) |scrobble| { appends: for (scrobbles) |scrobble| {
const filtered_scrobble: Data.Scrobble = blk: switch (@TypeOf(scrobble)) {
Data.IgnorantScrobble => {
if (scrobble.date > latest_timestamp * 1_000 or scrobble.date < earliest_timestamp * 1_000) { if (scrobble.date > latest_timestamp * 1_000 or scrobble.date < earliest_timestamp * 1_000) {
limited_tracks += 1; limited_tracks += 1;
continue :appends; continue :appends;
} }
const filtered_scrobble = Data.Scrobble{ break :blk Data.Scrobble{
.album = scrobble.album, .album = scrobble.album,
.artists_album = &[_][]const u8{scrobble.artist}, .artists_album = &[_][]const u8{scrobble.artist},
.track = scrobble.track, .track = scrobble.track,
.artists_track = &[_][]const u8{scrobble.artist}, .artists_track = &[_][]const u8{scrobble.artist},
.date = scrobble.date * 1_000, .date = scrobble.date * 1_000,
}; };
const complete_scrobble = if (rule_list) |rl| try rules.applyScrobbleRule(request.allocator, filtered_scrobble, rl) else filtered_scrobble;
const row = try Utils.scrobbleToRow(request.allocator, complete_scrobble);
try view_params.append(row);
try job_params.append(complete_scrobble);
}
}, },
.LastFMWeb => |scrobbles| { Data.SpotifyScrobble => {
for (scrobbles) |scrobble| {
const filtered_scrobble = Data.Scrobble{
.album = if (scrobble.album) |album| album.@"#text" else "Not Provided",
.artists_album = &[_][]const u8{scrobble.artist.@"#text"},
.track = scrobble.name,
.artists_track = &[_][]const u8{scrobble.artist.@"#text"},
.date = try std.fmt.parseInt(i64, scrobble.date.?.uts, 10) * 1_000_000,
};
const complete_scrobble = if (rule_list) |rl| try rules.applyScrobbleRule(request.allocator, filtered_scrobble, rl) else filtered_scrobble;
const row = try Utils.scrobbleToRow(request.allocator, complete_scrobble);
try view_params.append(row);
try job_params.append(complete_scrobble);
}
},
.Spotify => |scrobbles| {
appends: for (scrobbles) |scrobble| {
if (scrobble.ms_played < 30_000 and (scrobble.reason_end == null or !std.mem.eql(u8, scrobble.reason_end.?, "trackdone"))) { if (scrobble.ms_played < 30_000 and (scrobble.reason_end == null or !std.mem.eql(u8, scrobble.reason_end.?, "trackdone"))) {
skipped_tracks += 1; skipped_tracks += 1;
continue :appends; continue :appends;
@ -136,19 +113,45 @@ pub fn post(request: *jetzig.Request) !jetzig.View {
continue :appends; continue :appends;
} }
const filtered_scrobble = Data.Scrobble{ break :blk Data.Scrobble{
.album = scrobble.master_metadata_album_album_name.?, .album = scrobble.master_metadata_album_album_name.?,
.artists_album = &[_][]const u8{scrobble.master_metadata_album_artist_name.?}, .artists_album = &[_][]const u8{scrobble.master_metadata_album_artist_name.?},
.track = scrobble.master_metadata_track_name.?, .track = scrobble.master_metadata_track_name.?,
.artists_track = &[_][]const u8{scrobble.master_metadata_album_artist_name.?}, .artists_track = &[_][]const u8{scrobble.master_metadata_album_artist_name.?},
.date = (try zeit.instant(.{ .source = .{ .iso8601 = scrobble.ts } })).unixTimestamp() * 1_000_000, .date = (try zeit.instant(.{ .source = .{ .iso8601 = scrobble.ts } })).unixTimestamp() * 1_000_000,
}; };
},
Data.LastFMWebScrobble => {
break :blk Data.Scrobble{
.album = if (scrobble.album) |album| album.@"#text" else "Not Provided",
.artists_album = &[_][]const u8{scrobble.artist.@"#text"},
.track = scrobble.name,
.artists_track = &[_][]const u8{scrobble.artist.@"#text"},
.date = try std.fmt.parseInt(i64, scrobble.date.?.uts, 10) * 1_000_000,
};
},
else => unreachable,
};
const complete_scrobble = if (rule_list) |rl| try rules.applyScrobbleRule(request.allocator, filtered_scrobble, rl) else filtered_scrobble; const complete_scrobble = if (rule_list) |rl| try rules.applyScrobbleRule(request.allocator, filtered_scrobble, rl) else filtered_scrobble;
const row = try Utils.scrobbleToRow(request.allocator, complete_scrobble); const row = try Utils.scrobbleToRow(request.allocator, complete_scrobble);
try view_params.append(row); try view_params.append(row);
try job_params.append(complete_scrobble); var job_param = try job_params.append(.object);
try job_param.put("album", complete_scrobble.album);
try job_param.put("track", complete_scrobble.track);
try job_param.put("date", complete_scrobble.date);
var track_artists_array = try job_param.put("artists_track", .array);
for (complete_scrobble.artists_track) |a| {
try track_artists_array.append(a);
}
var album_artists_array = try job_param.put("artists_album", .array);
for (complete_scrobble.artists_album) |a| {
try album_artists_array.append(a);
}
} }
}, },
} }

View file

@ -20,27 +20,30 @@ pub fn entityQueryResult(request: *jetzig.Request, query: GeneratedQuery, args:
blk: while (try result.postgresql.result.next()) |entity_row| { blk: while (try result.postgresql.result.next()) |entity_row| {
switch (query.ResultType) { switch (query.ResultType) {
FirstlastResult, TimescaleResult, EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult, EntityItemsResult, AppearsResult, EntityInfoResult, EntityItemsSongResult => |T| { FirstlastResult, TimescaleResult, EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult, EntityItemsResult, AppearsResult, EntityInfoResult => |T| {
const entity = try entity_row.to(T, .{ .dupe = true, .allocator = request.allocator }); const entity = try entity_row.to(T, .{ .dupe = true, .allocator = request.allocator });
const item: ?TableRow = switch (query.ResultType) { const item: ?TableRow = switch (query.ResultType) {
EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult => switch (query.entity) { EntitiesScrobbleResult, EntitiesSongResult, EntitiesAlbumResult, EntitiesArtistResult => switch (query.entity) {
.artist => TableRow{ .artist = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles }, .artist => TableRow{ .artist = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles },
.scrobble, .song, .album => album_entities: { .album => album_entities: {
const last_artist = artist_list.getLastOrNull(); const last_artist = artist_list.getLastOrNull();
try artist_list.append(.{ .name = entity.artist_name, .id = entity.artist_id }); try artist_list.append(.{ .name = entity.artist_name, .id = entity.artist_id });
if (last_artist) |la| { if (last_artist) |la| {
if (la.id == entity.artist_id) continue :blk; if (la.id == entity.artist_id) continue :blk;
} }
break :album_entities switch (query.entity) { break :album_entities TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles };
.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 }, .song => song_entities: {
.album => TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles }, 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 :song_entities TableRow{ .song = .{ .name = entity.name, .id = entity.id }, .artistlist = try artist_list.toOwnedSlice(), .scrobbles = entity.scrobbles };
},
else => unreachable, else => unreachable,
};
}, },
}, EntityItemsResult => switch (query.entity) {
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 }, .artist => TableRow{ .album = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles },
.album => TableRow{ .song = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles }, .album => TableRow{ .song = .{ .name = entity.name, .id = entity.id }, .scrobbles = entity.scrobbles },
else => unreachable, else => unreachable,
@ -89,21 +92,10 @@ const TimescaleResult = struct { year: []const u8, scrobbles: i64 };
const EntitiesArtistResult = struct { name: []const u8, id: i32, 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 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 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 EntitiesScrobbleResult = struct { song_name: []const u8, song_id: i32, album_name: []const u8, album_id: i32, artist_name: []const u8, artist_id: i32, s_id: i32, date: i64 };
const EntityItemsResult = struct { name: []const u8, id: i32, scrobbles: i64 }; const EntityItemsResult = struct { name: []const u8, id: i32, scrobbles: i64 };
const AppearsResult = 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 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,
scrobbles: ?i64 = null,
date: ?[]const u8 = null,
};
pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQuery { pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQuery {
return GeneratedQuery{ return GeneratedQuery{
@ -118,11 +110,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
.album => EntitiesAlbumResult, .album => EntitiesAlbumResult,
.artist => EntitiesArtistResult, .artist => EntitiesArtistResult,
}, },
.entity_items => switch (entity) { .entity_items => EntityItemsResult,
.scrobble => unreachable,
.song => EntityItemsSongResult,
else => EntityItemsResult,
},
.appears => AppearsResult, .appears => AppearsResult,
.entity_info => EntityInfoResult, .entity_info => EntityInfoResult,
}, },
@ -132,49 +120,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) { switch (entity) {
.scrobble => unreachable, .scrobble => unreachable,
.song => .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 name, songs.id AS id, scrobbles.datetime AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\WHERE albumsongs.song_id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS 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
\\WHERE albumsongs.song_id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
.album =>
\\(SELECT songs.name AS name, songs.id AS 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
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\WHERE albums.id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS 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
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\WHERE albums.id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
.artist =>
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date
\\FROM albumsongs \\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
@ -185,7 +131,51 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
\\ \\
\\UNION ALL \\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 name, songs.id AS id, scrobbles.datetime AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\WHERE albumsongsartists.artist_id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
.album =>
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MM:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\WHERE albums.id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MM:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\WHERE albums.id = $1
\\ORDER BY scrobbles.datetime DESC
\\LIMIT 1)
,
.artist =>
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MM:SS') AS date
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\WHERE albumsongsartists.artist_id = $1
\\ORDER BY scrobbles.datetime ASC
\\LIMIT 1)
\\
\\UNION ALL
\\
\\(SELECT songs.name AS name, songs.id AS id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MM:SS') AS date
\\FROM albumsongs \\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong \\INNER JOIN scrobbles ON albumsongs.id = scrobbles.albumsong
@ -204,8 +194,9 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
\\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS year, COUNT(*) as scrobbles \\SELECT TO_CHAR(date_trunc('year', datetime), 'YYYY') AS year, COUNT(*) as scrobbles
\\FROM scrobbles \\FROM scrobbles
\\INNER JOIN albumsongs ON albumsongs.id = scrobbles.albumsong \\INNER JOIN albumsongs ON albumsongs.id = scrobbles.albumsong
\\INNER JOIN songs ON songs.id = albumsongs.song_id \\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\WHERE songs.id = $1 \\INNER JOIN artists ON artists.id = albumsongsartists.artist_id
\\WHERE artists.id = $1
\\GROUP BY year \\GROUP BY year
\\ORDER BY year ASC; \\ORDER BY year ASC;
, ,
@ -236,14 +227,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
//.ResultType = EntitiesResult, //.ResultType = EntitiesResult,
switch (entity) { switch (entity) {
.scrobble => .scrobble =>
\\SELECT songs.name AS song_name, songs.id AS song_id, albums.name AS album_name, albums.id AS album_id, artists.name AS artist_name, artists.id AS artist_id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date \\none
\\FROM albumsongs
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\INNER JOIN artists ON artists.id = albumsongsartists.artist_id
\\ORDER BY scrobbles.datetime ASC
, ,
.song => .song =>
\\SELECT songs.name, songs.id, artists.name, artists.id, COUNT(scrobbles) AS scrobbles \\SELECT songs.name, songs.id, artists.name, artists.id, COUNT(scrobbles) AS scrobbles
@ -281,21 +265,13 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) { switch (entity) {
.scrobble => unreachable, .scrobble => unreachable,
.song => .song =>
\\SELECT albums.name AS album_name, albums.id AS album_id, COUNT(scrobbles) AS scrobbles \\ NOTHING YET
\\FROM artistalbums
\\INNER JOIN albums ON albums.id = artistalbums.album_id
\\INNER JOIN albumsongs ON albumsongs.album_id = albums.id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\INNER JOIN albumsongsartists ON albumsongsartists.albumsong_id = albumsongs.id
\\WHERE albumsongs.song_id = $1
\\GROUP BY albums.id
\\ORDER BY scrobbles DESC;
, ,
.album => .album =>
\\nope \\nope
, ,
.artist => .artist =>
\\SELECT albums.name AS album_name, albums.id AS album_id, COUNT(scrobbles) AS scrobbles \\SELECT albums.name AS name, albums.id AS id, COUNT(scrobbles) AS scrobbles
\\FROM artistalbums \\FROM artistalbums
\\INNER JOIN albums ON albums.id = artistalbums.album_id \\INNER JOIN albums ON albums.id = artistalbums.album_id
\\INNER JOIN albumsongs ON albumsongs.album_id = albums.id \\INNER JOIN albumsongs ON albumsongs.album_id = albums.id
@ -312,13 +288,7 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
switch (entity) { switch (entity) {
.scrobble => unreachable, .scrobble => unreachable,
.song => .song =>
\\SELECT songs.name, songs.id, albums.name, albums.id, TO_CHAR(scrobbles.datetime, 'YYYY-MM-DD HH24:MI:SS') AS date \\get all scrobbles
\\FROM albumsongs
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\WHERE songs.id = $1
\\ORDER BY date ASC
, ,
.album => .album =>
\\SELECT songs.name, songs.id, COUNT(scrobbles) AS scrobbles \\SELECT songs.name, songs.id, COUNT(scrobbles) AS scrobbles
@ -344,19 +314,12 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
.entity_info => switch (entity) { .entity_info => switch (entity) {
.scrobble => unreachable, .scrobble => unreachable,
.song => .song =>
\\SELECT * FROM \\lol idk
\\(SELECT *, TO_CHAR(ROW_NUMBER() OVER (ORDER BY scrobbles DESC),'FM99999th') AS rank FROM
\\(SELECT songs.name AS name, songs.id AS id, COUNT(scrobbles) AS scrobbles
\\FROM albumsongs
\\INNER JOIN songs ON albumsongs.song_id = songs.id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
\\GROUP BY songs.id))
\\WHERE id = $1
, ,
.album => .album =>
\\SELECT * FROM \\SELECT * FROM
\\(SELECT *, TO_CHAR(ROW_NUMBER() OVER (ORDER BY scrobbles DESC),'FM9999th') AS rank FROM \\(SELECT *, TO_CHAR(ROW_NUMBER() OVER (ORDER BY scrobbles DESC),'FM9999th') AS rank FROM
\\(SELECT albums.name AS name, albums.id AS id, COUNT(scrobbles) AS scrobbles \\(SELECT albums.name, albums.id, COUNT(scrobbles) AS scrobbles
\\FROM albumsongs \\FROM albumsongs
\\INNER JOIN albums ON albumsongs.album_id = albums.id \\INNER JOIN albums ON albumsongs.album_id = albums.id
\\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id \\INNER JOIN scrobbles ON scrobbles.albumsong = albumsongs.id
@ -375,26 +338,6 @@ pub fn generateQuery(entity: EntityType, query_type: QueryTypeEnum) GeneratedQue
\\WHERE id = $1 \\WHERE id = $1
, ,
}, },
.datestreak => switch (entity) {
.song =>
\\SELECT songs.name, albums.name, streak.maxseq, streak.ds, streak.de 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.*,
\\((datetime::date - '1970-01-01'::date) - DENSE_RANK() OVER (PARTITION BY albumsong ORDER BY datetime::date)) AS grp
\\FROM scrobbles
\\) scrobbles
\\GROUP BY albumsong, grp
\\) scrobbles
\\GROUP BY albumsong, ds, de) AS streak
\\INNER JOIN albumsongs ON albumsongs.id = streak.albumsong
\\INNER JOIN albums ON albums.id = albumsongs.album_id
\\INNER JOIN songs ON songs.id = albumsongs.song_id
\\ORDER BY streak.maxseq DESC;
,
else => unreachable,
},
}, },
}; };
} }