Skip to content

Commit cc5e4bd

Browse files
authored
Merge pull request #4 from zarmstrong/new-table-test
created a new method of tracking redeemed keys, unique per platform
2 parents cb2486e + 0172968 commit cc5e4bd

File tree

3 files changed

+199
-74
lines changed

3 files changed

+199
-74
lines changed

Readme.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ mkdir -p ./data
4949

5050
## Usage
5151

52+
# ⚠️ Database Change Notice
53+
54+
**As of the 9/18/2025 version, the way redeemed keys are tracked has changed.**
55+
Redemption status is now tracked in a separate table for each key and platform combination.
56+
57+
**On first run after upgrade, all keys will be retried to ensure the database is properly marked. This may take a long time if you have a large key database.**
58+
This is expected and only happens once; subsequent runs will be fast.
59+
60+
## Usage Instructions
61+
5262
You can now specify exactly which platforms should redeem which games' SHiFT codes using the `--redeem` argument.
5363
**Recommended:** Use `--redeem` for fine-grained control.
5464
**Legacy:** You can still use `--games` and `--platforms` together, but a warning will be printed and all games will be redeemed on all platforms.

migrations.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def register(version: int):
4646

4747
def wrap(func):
4848
@wraps(func)
49-
def wrapper(conn):
49+
def wrapper(conn, *args, **kwargs): # Accept extra arguments for compatibility
5050
try:
5151
if func(conn):
5252
conn.cursor().execute("PRAGMA user_version = {}".format(version))
@@ -129,3 +129,67 @@ def update_1(conn: sqlite3.Connection):
129129
_L.error(f"'{e}' in\n{step}")
130130
return False
131131
return True
132+
133+
134+
@register(2)
135+
def migrate_redeemed_per_platform(conn):
136+
"""
137+
Ensure that each (code, game, platform) has its own redeemed status.
138+
If there are any rows with the same code/game but different platforms,
139+
ensure each has its own redeemed field.
140+
"""
141+
c = conn.cursor()
142+
# Check for duplicate codes across platforms
143+
c.execute(
144+
"""
145+
SELECT code, game, COUNT(DISTINCT platform) as platform_count
146+
FROM keys
147+
GROUP BY code, game
148+
HAVING platform_count > 1
149+
"""
150+
)
151+
duplicates = c.fetchall()
152+
# If there are duplicates, ensure each has its own redeemed field (already true in schema)
153+
# This migration is a no-op unless you want to do data cleanup.
154+
# Optionally, you could log or clean up here.
155+
return True
156+
157+
158+
@register(3)
159+
def migrate_redeemed_table(conn):
160+
"""
161+
Move redeemed status to a new redeemed_keys table and remove the redeemed column from keys.
162+
Do NOT migrate redeemed=1 rows, as we cannot know for which platforms they were redeemed.
163+
"""
164+
c = conn.cursor()
165+
# 1. Create new table if not exists
166+
c.execute(
167+
"""
168+
CREATE TABLE IF NOT EXISTS redeemed_keys (
169+
key_id INTEGER,
170+
platform TEXT,
171+
PRIMARY KEY (key_id, platform),
172+
FOREIGN KEY (key_id) REFERENCES keys(id)
173+
)
174+
"""
175+
)
176+
# 2. Remove redeemed column from keys (SQLite doesn't support DROP COLUMN directly)
177+
c.execute("PRAGMA table_info(keys)")
178+
columns = [col[1] for col in c.fetchall() if col[1] != "redeemed"]
179+
columns_str = ", ".join(columns)
180+
c.execute(f"ALTER TABLE keys RENAME TO keys_old")
181+
c.execute(
182+
f"""
183+
CREATE TABLE keys (
184+
id INTEGER primary key,
185+
reward TEXT,
186+
code TEXT,
187+
platform TEXT,
188+
game TEXT
189+
)
190+
"""
191+
)
192+
c.execute(f"INSERT INTO keys ({columns_str}) SELECT {columns_str} FROM keys_old")
193+
c.execute("DROP TABLE keys_old")
194+
conn.commit()
195+
return True

0 commit comments

Comments
 (0)