From 2db6e09aa3cf3289e1aaca0ce12121fb8e767aab Mon Sep 17 00:00:00 2001 From: Caleb Allen Date: Sat, 21 Mar 2026 15:40:34 -0400 Subject: [PATCH] fix: use sql.NullTime for last_played to handle NULL scan COALESCE(last_played, '') returned empty string which can't scan into time.Time. Removed COALESCE, use sql.NullTime instead. Format to string only when Valid. --- backend/database/sql/queries/audio_files.sql | 4 +-- .../database/sql/sqlcgen/audio_files.sql.go | 32 +++++++++++++------ backend/library/query.go | 18 +++++------ 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/backend/database/sql/queries/audio_files.sql b/backend/database/sql/queries/audio_files.sql index d0350c0..6337a8c 100644 --- a/backend/database/sql/queries/audio_files.sql +++ b/backend/database/sql/queries/audio_files.sql @@ -97,7 +97,7 @@ SELECT af.bitrate, af.file_size, af.play_count, - COALESCE(af.last_played, '') AS last_played + af.last_played FROM audio_files af JOIN recordings r ON af.recording_id = r.id JOIN artist_credit ac ON r.artist_credit_id = ac.id @@ -163,7 +163,7 @@ SELECT af.bitrate, af.file_size, af.play_count, - COALESCE(af.last_played, '') AS last_played + af.last_played FROM audio_files af JOIN recordings r ON af.recording_id = r.id JOIN artist_credit ac ON r.artist_credit_id = ac.id diff --git a/backend/database/sql/sqlcgen/audio_files.sql.go b/backend/database/sql/sqlcgen/audio_files.sql.go index 84539c8..40dd1b8 100644 --- a/backend/database/sql/sqlcgen/audio_files.sql.go +++ b/backend/database/sql/sqlcgen/audio_files.sql.go @@ -35,7 +35,7 @@ func (q *Queries) CountAudioFilesByLibrary(ctx context.Context, libraryID int64) const createAudioFile = `-- name: CreateAudioFile :one INSERT INTO audio_files (file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) -RETURNING id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id +RETURNING id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id, play_count, last_played ` type CreateAudioFileParams struct { @@ -80,6 +80,8 @@ func (q *Queries) CreateAudioFile(ctx context.Context, arg CreateAudioFileParams &i.FileSize, &i.Basename, &i.LibraryID, + &i.PlayCount, + &i.LastPlayed, ) return i, err } @@ -136,7 +138,7 @@ func (q *Queries) GetAllAudioFilePaths(ctx context.Context) ([]GetAllAudioFilePa } const getAllAudioFiles = `-- name: GetAllAudioFiles :many -SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id FROM audio_files +SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id, play_count, last_played FROM audio_files ` func (q *Queries) GetAllAudioFiles(ctx context.Context) ([]AudioFile, error) { @@ -161,6 +163,8 @@ func (q *Queries) GetAllAudioFiles(ctx context.Context) ([]AudioFile, error) { &i.FileSize, &i.Basename, &i.LibraryID, + &i.PlayCount, + &i.LastPlayed, ); err != nil { return nil, err } @@ -255,7 +259,7 @@ SELECT af.bitrate, af.file_size, af.play_count, - COALESCE(af.last_played, '') AS last_played + af.last_played FROM audio_files af JOIN recordings r ON af.recording_id = r.id JOIN artist_credit ac ON r.artist_credit_id = ac.id @@ -282,7 +286,7 @@ type GetAllTracksWithFullMetadataRow struct { Bitrate int64 FileSize int64 PlayCount int64 - LastPlayed string + LastPlayed sql.NullTime } func (q *Queries) GetAllTracksWithFullMetadata(ctx context.Context) ([]GetAllTracksWithFullMetadataRow, error) { @@ -352,7 +356,7 @@ SELECT af.bitrate, af.file_size, af.play_count, - COALESCE(af.last_played, '') AS last_played + af.last_played FROM audio_files af JOIN recordings r ON af.recording_id = r.id JOIN artist_credit ac ON r.artist_credit_id = ac.id @@ -380,7 +384,7 @@ type GetAllTracksWithFullMetadataByLibraryRow struct { Bitrate int64 FileSize int64 PlayCount int64 - LastPlayed string + LastPlayed sql.NullTime } func (q *Queries) GetAllTracksWithFullMetadataByLibrary(ctx context.Context, libraryID int64) ([]GetAllTracksWithFullMetadataByLibraryRow, error) { @@ -426,7 +430,7 @@ func (q *Queries) GetAllTracksWithFullMetadataByLibrary(ctx context.Context, lib } const getAudioFile = `-- name: GetAudioFile :one -SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id FROM audio_files +SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id, play_count, last_played FROM audio_files WHERE id = ? LIMIT 1 ` @@ -446,12 +450,14 @@ func (q *Queries) GetAudioFile(ctx context.Context, id int64) (AudioFile, error) &i.FileSize, &i.Basename, &i.LibraryID, + &i.PlayCount, + &i.LastPlayed, ) return i, err } const getAudioFileByPath = `-- name: GetAudioFileByPath :one -SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id FROM audio_files +SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id, play_count, last_played FROM audio_files WHERE file_path = ? LIMIT 1 ` @@ -471,12 +477,14 @@ func (q *Queries) GetAudioFileByPath(ctx context.Context, filePath string) (Audi &i.FileSize, &i.Basename, &i.LibraryID, + &i.PlayCount, + &i.LastPlayed, ) return i, err } const getAudioFilesByLibrary = `-- name: GetAudioFilesByLibrary :many -SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id FROM audio_files WHERE library_id = ? +SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id, play_count, last_played FROM audio_files WHERE library_id = ? ` func (q *Queries) GetAudioFilesByLibrary(ctx context.Context, libraryID int64) ([]AudioFile, error) { @@ -501,6 +509,8 @@ func (q *Queries) GetAudioFilesByLibrary(ctx context.Context, libraryID int64) ( &i.FileSize, &i.Basename, &i.LibraryID, + &i.PlayCount, + &i.LastPlayed, ); err != nil { return nil, err } @@ -707,7 +717,7 @@ func (q *Queries) GetAudioFilesByReleaseGroupByLibrary(ctx context.Context, arg } const getAudioFilesNeedingMetadata = `-- name: GetAudioFilesNeedingMetadata :many -SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id FROM audio_files +SELECT id, file_path, length_milliseconds, file_type_id, recording_id, sample_rate, bit_depth, channels, bitrate, file_size, basename, library_id, play_count, last_played FROM audio_files WHERE recording_id = 0 ` @@ -733,6 +743,8 @@ func (q *Queries) GetAudioFilesNeedingMetadata(ctx context.Context) ([]AudioFile &i.FileSize, &i.Basename, &i.LibraryID, + &i.PlayCount, + &i.LastPlayed, ); err != nil { return nil, err } diff --git a/backend/library/query.go b/backend/library/query.go index cae4bf6..f0c6e5b 100644 --- a/backend/library/query.go +++ b/backend/library/query.go @@ -67,11 +67,11 @@ func mapTrackRow( composer, fileType string, sampleRate, bitDepth, channels, bitrate, fileSize int64, playCount int64, - lastPlayed time.Time, + lastPlayed sql.NullTime, ) Track { var lastPlayedStr string - if !lastPlayed.IsZero() { - lastPlayedStr = lastPlayed.Format(time.DateTime) + if lastPlayed.Valid { + lastPlayedStr = lastPlayed.Time.Format(time.DateTime) } return Track{ @@ -210,7 +210,7 @@ func (l *Library) SearchTracks( row.Channels, row.Bitrate, row.FileSize, - 0, time.Time{}, + 0, sql.NullTime{}, )) } @@ -250,7 +250,7 @@ func (l *Library) GetAlbumTracks(albumID int64) ([]Track, error) { row.Channels, row.Bitrate, row.FileSize, - 0, time.Time{}, + 0, sql.NullTime{}, )) } @@ -425,7 +425,7 @@ func (l *Library) GetTracksByGenre( row.Channels, row.Bitrate, row.FileSize, - 0, time.Time{}, + 0, sql.NullTime{}, )) } @@ -741,7 +741,7 @@ func (l *Library) GetTracksByGenreByLibrary( row.Channels, row.Bitrate, row.FileSize, - 0, time.Time{}, + 0, sql.NullTime{}, )) } @@ -793,7 +793,7 @@ func (l *Library) GetAlbumTracksByLibrary( row.Channels, row.Bitrate, row.FileSize, - 0, time.Time{}, + 0, sql.NullTime{}, )) } @@ -841,7 +841,7 @@ func (l *Library) SearchTracksByLibrary( row.Channels, row.Bitrate, row.FileSize, - 0, time.Time{}, + 0, sql.NullTime{}, )) }