mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-31 07:30:32 +00:00
fix(db): keep album created_at in the driver's timestamp format when copying (#5867)
* fix(db): keep album created_at in the driver's timestamp format when copying Signed-off-by: IgorPolyakov <igorpolyakov@protonmail.com> * fix(db): move created_at renormalize migration after merged migrations The migration was versioned 20260813140000, which is older than 20260815015320 (already merged). goose.UpContext runs without WithAllowMissing, so any database that already applied the newer migration would fail with "found 1 missing migrations" and db.Init would log.Fatal on startup. --------- Signed-off-by: IgorPolyakov <igorpolyakov@protonmail.com> Co-authored-by: Deluan Quintão <deluan@navidrome.org>
This commit is contained in:
parent
5b758fc20c
commit
ea1e2b95a7
@ -0,0 +1,11 @@
|
||||
-- +goose Up
|
||||
|
||||
-- Repairs album.created_at values stored in RFC3339 T-format by CopyAttributes.
|
||||
-- These values sort incorrectly in "Recently Added", which compares timestamps as raw strings.
|
||||
|
||||
UPDATE album SET created_at = replace(replace(created_at, 'T', ' '), 'Z', '+00:00')
|
||||
WHERE created_at LIKE '%T%';
|
||||
|
||||
-- +goose Down
|
||||
|
||||
SELECT 1;
|
||||
@ -329,8 +329,11 @@ func (r *albumRepository) GetYears(libraryIDs ...int) ([]int, error) {
|
||||
}
|
||||
|
||||
func (r *albumRepository) CopyAttributes(fromID, toID string, columns ...string) error {
|
||||
// Cast values to text so go-sqlite3 does not decode datetime columns as time.Time
|
||||
// and reformat them as RFC3339 when written back.
|
||||
sel := slice.Map(columns, func(c string) string { return fmt.Sprintf("cast(%[1]s as text) as %[1]s", c) })
|
||||
var from dbx.NullStringMap
|
||||
err := r.queryOne(Select(columns...).From(r.tableName).Where(Eq{"id": fromID}), &from)
|
||||
err := r.queryOne(Select(sel...).From(r.tableName).Where(Eq{"id": fromID}), &from)
|
||||
if err != nil {
|
||||
return fmt.Errorf("getting album to copy fields from: %w", err)
|
||||
}
|
||||
|
||||
@ -19,6 +19,16 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
// rawColumn returns a column exactly as stored, bypassing go-sqlite3's decoding of
|
||||
// `datetime` columns into time.Time.
|
||||
func rawColumn(r sqlRepository, id, column string) string {
|
||||
var res struct{ Value string }
|
||||
sel := squirrel.Select("cast(" + column + " as text) as value").
|
||||
From(r.tableName).Where(squirrel.Eq{"id": id})
|
||||
ExpectWithOffset(1, r.queryOne(sel, &res)).To(Succeed())
|
||||
return res.Value
|
||||
}
|
||||
|
||||
var _ = Describe("AlbumRepository", func() {
|
||||
var albumRepo *albumRepository
|
||||
var ctx context.Context
|
||||
@ -69,6 +79,22 @@ var _ = Describe("AlbumRepository", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(got.CreatedAt).To(BeTemporally("~", dstTime, time.Second))
|
||||
})
|
||||
It("returns not found and leaves destination untouched when source does not exist", func() {
|
||||
err := albumRepo.CopyAttributes("copy-missing", "copy-dst", "created_at")
|
||||
Expect(errors.Is(err, model.ErrNotFound)).To(BeTrue())
|
||||
got, getErr := albumRepo.Get("copy-dst")
|
||||
Expect(getErr).ToNot(HaveOccurred())
|
||||
Expect(got.CreatedAt).To(BeTemporally("~", dstTime, time.Second))
|
||||
})
|
||||
It("keeps the copied created_at in the driver's space-separated format", func() {
|
||||
// Copying through a Go string would rewrite it as RFC3339 ("2020-01-02T03:04:05Z"),
|
||||
// which string-sorts above every space-format timestamp and pins the album to the
|
||||
// top of "Recently Added".
|
||||
Expect(albumRepo.CopyAttributes("copy-src", "copy-dst", "created_at")).To(Succeed())
|
||||
Expect(rawColumn(albumRepo.sqlRepository, "copy-dst", "created_at")).
|
||||
To(Equal(rawColumn(albumRepo.sqlRepository, "copy-src", "created_at")))
|
||||
Expect(rawColumn(albumRepo.sqlRepository, "copy-dst", "created_at")).ToNot(ContainSubstring("T"))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("GetCursor", func() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user