fix an issue with db
CI / check (22) (push) Failing after 4m50s
CI / check (24) (push) Failing after 4m56s

This commit is contained in:
2026-10-13 18:28:07 +02:00
parent d5d886ac5f
commit 5765922765
2 changed files with 54 additions and 1 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ export function createDatabase(config) {
const db = new Database(config.dbPath);
initializeSchema(db);
runMigrations(db, config);
initializeAttachments(db);
runMigrations(db, config);
return db;
}
+53
View File
@@ -265,6 +265,59 @@ export function runMigrations(db, {dropLegacyChats = false} = {}) {
ensureColumn("users", userColumns, "role", "ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('user', 'admin'))");
ensureColumn("users", userColumns, "session_version", "ALTER TABLE users ADD COLUMN session_version INTEGER DEFAULT 0");
db.prepare("UPDATE users SET session_version = 0 WHERE session_version IS NULL").run();
// Older databases allowed usernames that differed only by case. Repair those
// rows before adding the case-insensitive uniqueness guarantee. Keep the first
// account unchanged and give later accounts a stable, recoverable username;
// moving their owned rows prevents orphaned workspace data.
const conflictingUsers = db.prepare(`
SELECT LOWER(username) AS username_lower
FROM users
GROUP BY LOWER(username)
HAVING COUNT(*) > 1
`).all();
if (conflictingUsers.length > 0) {
const ownershipColumns = [
["chat_sessions", "username"],
["chat_memories", "username"],
["persona_chat_state", "username"],
["personas", "username"],
["personas", "source_creator_username"],
["user_settings", "username"],
["persona_market", "creator_username"],
["persona_versions", "username"],
["prompt_templates", "username"],
["persona_market_favorites", "username"],
["persona_market_ratings", "username"],
["persona_market_reports", "reporter_username"],
["attachments", "username"],
["upload_leases", "username"],
["workspace_operation_leases", "username"]
];
const existingTables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map(({name}) => name));
const updateStatements = ownershipColumns
.filter(([table]) => existingTables.has(table))
.map(([table, column]) => [
table,
column,
db.prepare(`UPDATE "${table}" SET "${column}" = ? WHERE "${column}" = ?`)
]);
const repairConflicts = db.transaction(() => {
db.pragma("defer_foreign_keys = ON");
for (const {username_lower: usernameLower} of conflictingUsers) {
const rows = db.prepare("SELECT rowid, username FROM users WHERE LOWER(username) = ? ORDER BY rowid").all(usernameLower);
for (const row of rows.slice(1)) {
const suffix = `-legacy-${row.rowid}`;
const nextUsername = `${row.username.slice(0, Math.max(1, 64 - suffix.length))}${suffix}`;
for (const [, , statement] of updateStatements) {
statement.run(nextUsername, row.username);
}
db.prepare("UPDATE users SET username = ? WHERE username = ?").run(nextUsername, row.username);
}
}
});
repairConflicts();
}
db.exec("CREATE UNIQUE INDEX IF NOT EXISTS users_username_lower ON users (LOWER(username))");
const personaColumns = db.prepare("PRAGMA table_info(personas)").all();