Bookmark dedup is keyed on hash(title + position bucket), but the table also enforces UNIQUE(media_item_id, user_id, title). When a client re- saves the same bookmark title with a changed position form - e.g. the Android app upgrading a percentage-only row to an EPUB CFI, or a web and app bookmark landing on the same 'Bookmark at 44%' title - the dedup-key lookup misses and the INSERT violates the title constraint, returning HTTP 500 and failing the sync. A title collision on the same (user, item) is by definition the same bookmark slot, so take the LWW semantics all the way: ON CONFLICT DO UPDATE replaces position/cfi_position/page/chapter/percentage, refreshes dedup_key and timestamps, merges device_sync_data, and - matching UpdateMediaBookmarkForSync - clears deleted/deleted_at so a re-create resurrects a tombstoned title slot instead of leaving an invisible row holding it. Device sync flows are unaffected: KOReader/Kobo pushes that carry their own dedup-key echoes never reach the INSERT, and same-key saves still go through applyBookmarkLWW with its tombstone freshness checks.
33 lines
570 B
Go
33 lines
570 B
Go
// Code generated by sqlc. DO NOT EDIT.
|
|
// versions:
|
|
// sqlc v1.31.1
|
|
|
|
package database
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/jackc/pgx/v5"
|
|
"github.com/jackc/pgx/v5/pgconn"
|
|
)
|
|
|
|
type DBTX interface {
|
|
Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error)
|
|
Query(context.Context, string, ...interface{}) (pgx.Rows, error)
|
|
QueryRow(context.Context, string, ...interface{}) pgx.Row
|
|
}
|
|
|
|
func New(db DBTX) *Queries {
|
|
return &Queries{db: db}
|
|
}
|
|
|
|
type Queries struct {
|
|
db DBTX
|
|
}
|
|
|
|
func (q *Queries) WithTx(tx pgx.Tx) *Queries {
|
|
return &Queries{
|
|
db: tx,
|
|
}
|
|
}
|