fix(conflicts): use ListConflictsByUser in DismissAllResolved so resolved conflicts are found
DismissAllResolved was calling ListSyncConflictsByUser which filters to 'unresolved' conflicts only, so it could never find the user_resolved or bulk_resolved conflicts it was trying to delete. The query always returned an empty set, making dismiss-all a no-op. Fix the leading space in three SQL query name annotations (ListConflictsByUser, ListAllConflictsByUserAndStatus, CheckForProgressConflicts) that prevented sqlc from generating their Go functions. Regenerate the query code and swap DismissAllResolved to use ListConflictsByUser (no status filter) — the existing Go loop already filters by resolution_status.
This commit is contained in:
@@ -23,6 +23,7 @@ type Querier interface {
|
||||
// Bulk update format group for all media items
|
||||
BulkUpdateFormatGroups(ctx context.Context) error
|
||||
BulkUpdateProgressFromSync(ctx context.Context, arg BulkUpdateProgressFromSyncParams) ([]interface{}, error)
|
||||
CheckForProgressConflicts(ctx context.Context, arg CheckForProgressConflictsParams) (int64, error)
|
||||
// Cleanup expired OPDS tokens
|
||||
CleanupExpiredOpdsTokens(ctx context.Context) error
|
||||
CleanupExpiredRefreshTokens(ctx context.Context) error
|
||||
@@ -275,7 +276,9 @@ type Querier interface {
|
||||
IsBookOnKoboShelf(ctx context.Context, arg IsBookOnKoboShelfParams) (bool, error)
|
||||
// Link unlinked book to media item
|
||||
LinkUnlinkedBook(ctx context.Context, arg LinkUnlinkedBookParams) (UnlinkedBooks, error)
|
||||
ListAllConflictsByUserAndStatus(ctx context.Context, arg ListAllConflictsByUserAndStatusParams) ([]ListAllConflictsByUserAndStatusRow, error)
|
||||
ListAllSyncQueueItems(ctx context.Context, arg ListAllSyncQueueItemsParams) ([]ListAllSyncQueueItemsRow, error)
|
||||
ListConflictsByUser(ctx context.Context, userID pgtype.UUID) ([]ListConflictsByUserRow, error)
|
||||
ListDevicesByType(ctx context.Context, deviceType string) ([]Devices, error)
|
||||
ListDevicesByUser(ctx context.Context, userID pgtype.UUID) ([]Devices, error)
|
||||
ListLibraries(ctx context.Context) ([]ListLibrariesRow, error)
|
||||
|
||||
@@ -153,6 +153,28 @@ func (q *Queries) BulkUpdateProgressFromSync(ctx context.Context, arg BulkUpdate
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const CheckForProgressConflicts = `-- name: CheckForProgressConflicts :one
|
||||
SELECT COUNT(*) as conflict_count
|
||||
FROM reading_progress
|
||||
WHERE media_item_id = $1
|
||||
AND user_id = $2
|
||||
AND last_sync_timestamp > NOW() - INTERVAL '5 minutes'
|
||||
AND last_sync_source != $3
|
||||
`
|
||||
|
||||
type CheckForProgressConflictsParams struct {
|
||||
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
|
||||
UserID pgtype.UUID `db:"user_id" json:"user_id"`
|
||||
LastSyncSource pgtype.Text `db:"last_sync_source" json:"last_sync_source"`
|
||||
}
|
||||
|
||||
func (q *Queries) CheckForProgressConflicts(ctx context.Context, arg CheckForProgressConflictsParams) (int64, error) {
|
||||
row := q.db.QueryRow(ctx, CheckForProgressConflicts, arg.MediaItemID, arg.UserID, arg.LastSyncSource)
|
||||
var conflict_count int64
|
||||
err := row.Scan(&conflict_count)
|
||||
return conflict_count, err
|
||||
}
|
||||
|
||||
const CleanupExpiredOpdsTokens = `-- name: CleanupExpiredOpdsTokens :exec
|
||||
DELETE FROM opds_tokens WHERE expires_at < NOW()
|
||||
`
|
||||
@@ -6322,6 +6344,67 @@ func (q *Queries) LinkUnlinkedBook(ctx context.Context, arg LinkUnlinkedBookPara
|
||||
return i, err
|
||||
}
|
||||
|
||||
const ListAllConflictsByUserAndStatus = `-- name: ListAllConflictsByUserAndStatus :many
|
||||
SELECT sc.id, sc.media_item_id, sc.user_id, sc.conflict_type, sc.conflict_data, sc.resolution_status, sc.resolution_data, sc.resolved_by, sc.resolved_at, sc.created_at, mi.title, mi.author
|
||||
FROM sync_conflicts sc
|
||||
JOIN media_items mi ON sc.media_item_id = mi.id
|
||||
WHERE sc.user_id = $1 AND sc.resolution_status = $2
|
||||
ORDER BY sc.created_at DESC
|
||||
`
|
||||
|
||||
type ListAllConflictsByUserAndStatusParams struct {
|
||||
UserID pgtype.UUID `db:"user_id" json:"user_id"`
|
||||
ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"`
|
||||
}
|
||||
|
||||
type ListAllConflictsByUserAndStatusRow struct {
|
||||
ID pgtype.UUID `db:"id" json:"id"`
|
||||
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
|
||||
UserID pgtype.UUID `db:"user_id" json:"user_id"`
|
||||
ConflictType string `db:"conflict_type" json:"conflict_type"`
|
||||
ConflictData []byte `db:"conflict_data" json:"conflict_data"`
|
||||
ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"`
|
||||
ResolutionData []byte `db:"resolution_data" json:"resolution_data"`
|
||||
ResolvedBy pgtype.UUID `db:"resolved_by" json:"resolved_by"`
|
||||
ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
|
||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||
Title string `db:"title" json:"title"`
|
||||
Author pgtype.Text `db:"author" json:"author"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListAllConflictsByUserAndStatus(ctx context.Context, arg ListAllConflictsByUserAndStatusParams) ([]ListAllConflictsByUserAndStatusRow, error) {
|
||||
rows, err := q.db.Query(ctx, ListAllConflictsByUserAndStatus, arg.UserID, arg.ResolutionStatus)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []ListAllConflictsByUserAndStatusRow{}
|
||||
for rows.Next() {
|
||||
var i ListAllConflictsByUserAndStatusRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.MediaItemID,
|
||||
&i.UserID,
|
||||
&i.ConflictType,
|
||||
&i.ConflictData,
|
||||
&i.ResolutionStatus,
|
||||
&i.ResolutionData,
|
||||
&i.ResolvedBy,
|
||||
&i.ResolvedAt,
|
||||
&i.CreatedAt,
|
||||
&i.Title,
|
||||
&i.Author,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const ListAllSyncQueueItems = `-- name: ListAllSyncQueueItems :many
|
||||
SELECT
|
||||
sq.id, sq.device_id, sq.media_item_id, sq.sync_type, sq.sync_data, sq.priority, sq.attempts, sq.max_attempts, sq.status, sq.error_message, sq.created_at, sq.processed_at,
|
||||
@@ -6398,6 +6481,62 @@ func (q *Queries) ListAllSyncQueueItems(ctx context.Context, arg ListAllSyncQueu
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const ListConflictsByUser = `-- name: ListConflictsByUser :many
|
||||
SELECT sc.id, sc.media_item_id, sc.user_id, sc.conflict_type, sc.conflict_data, sc.resolution_status, sc.resolution_data, sc.resolved_by, sc.resolved_at, sc.created_at, mi.title, mi.author
|
||||
FROM sync_conflicts sc
|
||||
JOIN media_items mi ON sc.media_item_id = mi.id
|
||||
WHERE sc.user_id = $1
|
||||
ORDER BY sc.created_at DESC
|
||||
`
|
||||
|
||||
type ListConflictsByUserRow struct {
|
||||
ID pgtype.UUID `db:"id" json:"id"`
|
||||
MediaItemID pgtype.UUID `db:"media_item_id" json:"media_item_id"`
|
||||
UserID pgtype.UUID `db:"user_id" json:"user_id"`
|
||||
ConflictType string `db:"conflict_type" json:"conflict_type"`
|
||||
ConflictData []byte `db:"conflict_data" json:"conflict_data"`
|
||||
ResolutionStatus pgtype.Text `db:"resolution_status" json:"resolution_status"`
|
||||
ResolutionData []byte `db:"resolution_data" json:"resolution_data"`
|
||||
ResolvedBy pgtype.UUID `db:"resolved_by" json:"resolved_by"`
|
||||
ResolvedAt pgtype.Timestamptz `db:"resolved_at" json:"resolved_at"`
|
||||
CreatedAt pgtype.Timestamptz `db:"created_at" json:"created_at"`
|
||||
Title string `db:"title" json:"title"`
|
||||
Author pgtype.Text `db:"author" json:"author"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListConflictsByUser(ctx context.Context, userID pgtype.UUID) ([]ListConflictsByUserRow, error) {
|
||||
rows, err := q.db.Query(ctx, ListConflictsByUser, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
items := []ListConflictsByUserRow{}
|
||||
for rows.Next() {
|
||||
var i ListConflictsByUserRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.MediaItemID,
|
||||
&i.UserID,
|
||||
&i.ConflictType,
|
||||
&i.ConflictData,
|
||||
&i.ResolutionStatus,
|
||||
&i.ResolutionData,
|
||||
&i.ResolvedBy,
|
||||
&i.ResolvedAt,
|
||||
&i.CreatedAt,
|
||||
&i.Title,
|
||||
&i.Author,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const ListDevicesByType = `-- name: ListDevicesByType :many
|
||||
SELECT id, user_id, device_name, device_type, device_identifier, auth_token, last_sync, last_seen, sync_enabled, auto_sync, sync_frequency_minutes, device_metadata, created_at, updated_at FROM devices WHERE device_type = $1 ORDER BY created_at DESC
|
||||
`
|
||||
|
||||
@@ -1099,19 +1099,19 @@ RETURNING *;
|
||||
-- name: DeleteSyncConflict :exec
|
||||
DELETE FROM sync_conflicts WHERE id = $1;
|
||||
|
||||
-- name: ListAllConflictsByUserAndStatus :many
|
||||
SELECT sc.*, mi.title, mi.author
|
||||
FROM sync_conflicts sc
|
||||
JOIN media_items mi ON sc.media_item_id = mi.id
|
||||
WHERE sc.user_id = $1 AND sc.resolution_status = $2
|
||||
ORDER BY sc.created_at DESC;
|
||||
-- name: ListAllConflictsByUserAndStatus :many
|
||||
SELECT sc.*, mi.title, mi.author
|
||||
FROM sync_conflicts sc
|
||||
JOIN media_items mi ON sc.media_item_id = mi.id
|
||||
WHERE sc.user_id = $1 AND sc.resolution_status = $2
|
||||
ORDER BY sc.created_at DESC;
|
||||
|
||||
-- name: ListConflictsByUser :many
|
||||
SELECT sc.*, mi.title, mi.author
|
||||
FROM sync_conflicts sc
|
||||
JOIN media_items mi ON sc.media_item_id = mi.id
|
||||
WHERE sc.user_id = $1
|
||||
ORDER BY sc.created_at DESC;
|
||||
-- name: ListConflictsByUser :many
|
||||
SELECT sc.*, mi.title, mi.author
|
||||
FROM sync_conflicts sc
|
||||
JOIN media_items mi ON sc.media_item_id = mi.id
|
||||
WHERE sc.user_id = $1
|
||||
ORDER BY sc.created_at DESC;
|
||||
|
||||
-- ============================================
|
||||
-- KOREADER SYNC PROTOCOL
|
||||
@@ -1216,7 +1216,7 @@ WHERE lv.user_id = $1
|
||||
ORDER BY mi.title ASC
|
||||
LIMIT 1000;
|
||||
|
||||
-- name: CheckForProgressConflicts :one
|
||||
-- name: CheckForProgressConflicts :one
|
||||
SELECT COUNT(*) as conflict_count
|
||||
FROM reading_progress
|
||||
WHERE media_item_id = $1
|
||||
|
||||
@@ -401,7 +401,7 @@ func (h *ConflictHandler) DeleteConflict(c *echo.Context) error {
|
||||
func (h *ConflictHandler) DismissAllResolved(c *echo.Context) error {
|
||||
user := c.Get("user").(database.Users)
|
||||
|
||||
conflicts, err := h.db.ListSyncConflictsByUser(context.Background(), user.ID)
|
||||
conflicts, err := h.db.ListConflictsByUser(context.Background(), user.ID)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "failed to list conflicts")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user