Every comment naming a path in flutter_client/ now resolves to nothing, which is the failure mode this project has already been bitten by twice -- drift #572 came from delete.go describing behaviour it no longer had, and that same docstring was still wrong when it was fixed last week. A pointer to a deleted directory is the same thing in slower motion: the reader follows it, finds nothing, and cannot tell whether the comment is stale or they are looking in the wrong place. Three treatments, per what each comment was actually doing: - Naming a concept ("mirrors db.dart's CachedTracks Drift table"): keep the concept, drop the path. The Drift table is why the entity looks as it does; the file it lived in is not. - Pure port bookkeeping ("Mirrors <path>." and nothing else): deleted. Git history records the port; the comment only restated it. - Substance introduced by a pointer (a lifecycle list, a 200 px/s threshold, an inverted control-row placement): keep the substance, drop the lead-in. The two Go comments were the valuable ones and got more than a trim. They stated a live contract -- "field names match the client's FromJson helpers exactly, or fields are silently dropped" -- against a client that no longer exists. They now name the real consumer, SyncResponseWire.kt, and say why the failure is silent there too: kotlinx.serialization skips unknown keys, so a renamed field arrives as a default value rather than an error. The ticket counted 64 files by grepping flutter_client/. A second tier turned up during the sweep: 15 more references naming bare Dart files (player_bar.dart, now_playing_screen.dart:464, auth_provider.dart) with no directory prefix. Same dead tree, same treatment, folded in here. Comments only -- verified no non-comment line is touched in the diff.
124 lines
3.9 KiB
Go
124 lines
3.9 KiB
Go
package api
|
|
|
|
// Wire shapes for /api/library/sync upserts. The sqlc-generated row
|
|
// structs (dbq.Artist, dbq.Album, dbq.Track, dbq.Playlist) have no
|
|
// JSON tags (sqlc.yaml: emit_json_tags=false), so a raw json.Marshal
|
|
// of them produces PascalCase field names that the Flutter sync
|
|
// controller (which reads snake_case keys) can't parse.
|
|
//
|
|
// These view structs add the JSON tag layer + flatten pgtype.UUID and
|
|
// pgtype.Timestamptz / Date into strings, mirroring the pattern
|
|
// playlistRowView already established for /api/playlists.
|
|
//
|
|
// Field names match what the Android client deserialises in
|
|
// models/wire/SyncResponseWire.kt (Sync{Artist,Album,Track}Wire) exactly.
|
|
// Adding a field server-side requires a matching @SerialName there or it is
|
|
// silently dropped — kotlinx.serialization ignores unknown keys, so the
|
|
// failure is a missing value at runtime, not an error at parse time.
|
|
|
|
import (
|
|
"git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq"
|
|
syncpkg "git.fabledsword.com/bvandeusen/minstrel/internal/sync"
|
|
)
|
|
|
|
type artistSyncView struct {
|
|
ID string `json:"id"`
|
|
Name string `json:"name"`
|
|
SortName string `json:"sort_name"`
|
|
Mbid *string `json:"mbid"`
|
|
ArtistThumbPath *string `json:"artist_thumb_path"`
|
|
ArtistFanartPath *string `json:"artist_fanart_path"`
|
|
}
|
|
|
|
func toArtistSyncView(a dbq.Artist) artistSyncView {
|
|
return artistSyncView{
|
|
ID: syncpkg.FormatUUID(a.ID),
|
|
Name: a.Name,
|
|
SortName: a.SortName,
|
|
Mbid: a.Mbid,
|
|
ArtistThumbPath: a.ArtistThumbPath,
|
|
ArtistFanartPath: a.ArtistFanartPath,
|
|
}
|
|
}
|
|
|
|
type albumSyncView struct {
|
|
ID string `json:"id"`
|
|
ArtistID string `json:"artist_id"`
|
|
Title string `json:"title"`
|
|
SortTitle string `json:"sort_title"`
|
|
ReleaseDate *string `json:"release_date"`
|
|
CoverArtPath *string `json:"cover_art_path"`
|
|
Mbid *string `json:"mbid"`
|
|
}
|
|
|
|
func toAlbumSyncView(a dbq.Album) albumSyncView {
|
|
var releaseDate *string
|
|
if a.ReleaseDate.Valid {
|
|
s := a.ReleaseDate.Time.Format("2006-01-02")
|
|
releaseDate = &s
|
|
}
|
|
return albumSyncView{
|
|
ID: syncpkg.FormatUUID(a.ID),
|
|
ArtistID: syncpkg.FormatUUID(a.ArtistID),
|
|
Title: a.Title,
|
|
SortTitle: a.SortTitle,
|
|
ReleaseDate: releaseDate,
|
|
CoverArtPath: a.CoverArtPath,
|
|
Mbid: a.Mbid,
|
|
}
|
|
}
|
|
|
|
type trackSyncView struct {
|
|
ID string `json:"id"`
|
|
AlbumID string `json:"album_id"`
|
|
ArtistID string `json:"artist_id"`
|
|
Title string `json:"title"`
|
|
DurationMs int32 `json:"duration_ms"`
|
|
TrackNumber *int32 `json:"track_number"`
|
|
DiscNumber *int32 `json:"disc_number"`
|
|
FilePath string `json:"file_path"`
|
|
FileFormat string `json:"file_format"`
|
|
Genre *string `json:"genre"`
|
|
}
|
|
|
|
func toTrackSyncView(t dbq.Track) trackSyncView {
|
|
return trackSyncView{
|
|
ID: syncpkg.FormatUUID(t.ID),
|
|
AlbumID: syncpkg.FormatUUID(t.AlbumID),
|
|
ArtistID: syncpkg.FormatUUID(t.ArtistID),
|
|
Title: t.Title,
|
|
DurationMs: t.DurationMs,
|
|
TrackNumber: t.TrackNumber,
|
|
DiscNumber: t.DiscNumber,
|
|
FilePath: t.FilePath,
|
|
FileFormat: t.FileFormat,
|
|
Genre: t.Genre,
|
|
}
|
|
}
|
|
|
|
type playlistSyncView struct {
|
|
ID string `json:"id"`
|
|
UserID string `json:"user_id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
IsPublic bool `json:"is_public"`
|
|
CoverPath *string `json:"cover_path"`
|
|
TrackCount int32 `json:"track_count"`
|
|
DurationSec int32 `json:"duration_sec"`
|
|
SystemVariant *string `json:"system_variant"`
|
|
}
|
|
|
|
func toPlaylistSyncView(p dbq.Playlist) playlistSyncView {
|
|
return playlistSyncView{
|
|
ID: syncpkg.FormatUUID(p.ID),
|
|
UserID: syncpkg.FormatUUID(p.UserID),
|
|
Name: p.Name,
|
|
Description: p.Description,
|
|
IsPublic: p.IsPublic,
|
|
CoverPath: p.CoverPath,
|
|
TrackCount: p.TrackCount,
|
|
DurationSec: p.DurationSec,
|
|
SystemVariant: p.SystemVariant,
|
|
}
|
|
}
|