feat(podcasts): widen reader_settings key ceiling — item 2.1 foundation
reader_settings.setting_key was VARCHAR(50), and the composite podcast_order:<uuid> key already sits at exactly 50 chars — zero headroom. The deferred queue-editor idea (plan §0 item 2b) and any future per-feed/per-collection preference key would have been forced to payload-stuff inside the order row by a column width. Composite prefix:<uuid> keys are the norm now (§10 R5), so the ceiling widens to VARCHAR(120): idempotent in-place ALTER (varchar widening is metadata-only, no table rewrite), re-runs harmlessly on every boot per the schema convention. No new episode-membership tables: collection_items already carries ordered playlist membership (position, A2c) against media_items, which podcast episodes ARE — episodes join collections through the existing table. Pinned by TestReaderSettingsCompositeKeyHeadroom: a 57-char composite key (the podcast_custom_order:<uuid> shape) upserts and reads back. Under the old width this fails; sqlc codegen is byte-identical.
This commit is contained in:
1 parent
f7ba4d24d6
commit
7bf0b1257d
2 files changed
+36
-1
No files matched your search
@@ -471,6 +471,34 @@ func TestDeleteMediaItemPodcastGuard(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---- reader_settings key width (§10 R5, item 2.1): composite
|
||||||
|
// prefix:<uuid> keys have headroom past the old 50-char ceiling ----
|
||||||
|
|
||||||
|
func TestReaderSettingsCompositeKeyHeadroom(t *testing.T) {
|
||||||
|
setup := setupTestServer(t)
|
||||||
|
userID := getRegularUserID(t, setup.DB)
|
||||||
|
|
||||||
|
// 57 chars — the deferred podcast_custom_order:<uuid> shape. Under
|
||||||
|
// the old VARCHAR(50) this upsert fails; the widening (item 2.1)
|
||||||
|
// makes it ordinary preference state.
|
||||||
|
key := "podcast_custom_order:01921a2b-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
|
||||||
|
require.Len(t, key, 57, "sentinel: the pinned key must exceed the old VARCHAR(50)")
|
||||||
|
|
||||||
|
err := setup.DB.UpsertUserSettingByKey(seedCtx(), database.UpsertUserSettingByKeyParams{
|
||||||
|
UserID: pgtype.UUID{Bytes: userID, Valid: true},
|
||||||
|
SettingKey: key,
|
||||||
|
SettingValue: []byte(`{"order":"custom"}`),
|
||||||
|
})
|
||||||
|
require.NoError(t, err, "composite keys longer than 50 chars must store (VARCHAR(120) headroom)")
|
||||||
|
|
||||||
|
val, err := setup.DB.GetUserSettingByKey(seedCtx(), database.GetUserSettingByKeyParams{
|
||||||
|
UserID: pgtype.UUID{Bytes: userID, Valid: true},
|
||||||
|
SettingKey: key,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.JSONEq(t, `{"order":"custom"}`, string(val))
|
||||||
|
}
|
||||||
|
|
||||||
// ---- download worker: state machine, idempotency, file layout ----
|
// ---- download worker: state machine, idempotency, file layout ----
|
||||||
|
|
||||||
func TestPodcastDownloadWorker(t *testing.T) {
|
func TestPodcastDownloadWorker(t *testing.T) {
|
||||||
|
|||||||
@@ -1628,12 +1628,19 @@ CREATE INDEX IF NOT EXISTS idx_dictionary_word ON dictionary_cache(word);
|
|||||||
CREATE TABLE IF NOT EXISTS reader_settings (
|
CREATE TABLE IF NOT EXISTS reader_settings (
|
||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
setting_key VARCHAR(50) NOT NULL,
|
setting_key VARCHAR(120) NOT NULL,
|
||||||
setting_value JSONB NOT NULL,
|
setting_value JSONB NOT NULL,
|
||||||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||||
UNIQUE(user_id, setting_key)
|
UNIQUE(user_id, setting_key)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Key-width headroom (podcast plan §10 R5, item 2.1): the composite
|
||||||
|
-- `podcast_order:<uuid>` key sits at exactly 50 chars, and future
|
||||||
|
-- per-feed/per-collection preference keys must not be forced to
|
||||||
|
-- payload-stuff by a column width. Widening a varchar is metadata-only
|
||||||
|
-- (no table rewrite); idempotent on every boot.
|
||||||
|
ALTER TABLE reader_settings ALTER COLUMN setting_key TYPE VARCHAR(120);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_reader_settings_user ON reader_settings(user_id);
|
CREATE INDEX IF NOT EXISTS idx_reader_settings_user ON reader_settings(user_id);
|
||||||
|
|
||||||
-- PDF bookmarks (custom user bookmarks)
|
-- PDF bookmarks (custom user bookmarks)
|
||||||
|
|||||||
Reference in new issue
Block a user