forked from trent_larson/crowd-funder-for-time-pwa
IndexedDB migration: fix settings update
This commit is contained in:
@@ -898,6 +898,10 @@ export function generateComparisonYaml(comparison: DataComparison): string {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* I recommend using the existing contact import view to migrate contacts.
|
||||||
|
*
|
||||||
export async function migrateContacts(
|
export async function migrateContacts(
|
||||||
overwriteExisting: boolean = false,
|
overwriteExisting: boolean = false,
|
||||||
): Promise<MigrationResult> {
|
): Promise<MigrationResult> {
|
||||||
@@ -976,6 +980,8 @@ export async function migrateContacts(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrates specific settings fields from Dexie to SQLite database
|
* Migrates specific settings fields from Dexie to SQLite database
|
||||||
@@ -991,13 +997,12 @@ export async function migrateContacts(
|
|||||||
*
|
*
|
||||||
* @async
|
* @async
|
||||||
* @function migrateSettings
|
* @function migrateSettings
|
||||||
* @param {boolean} [overwriteExisting=false] - Whether to overwrite existing settings in SQLite
|
|
||||||
* @returns {Promise<MigrationResult>} Detailed results of the migration operation
|
* @returns {Promise<MigrationResult>} Detailed results of the migration operation
|
||||||
* @throws {Error} If the migration process fails completely
|
* @throws {Error} If the migration process fails completely
|
||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
* try {
|
* try {
|
||||||
* const result = await migrateSettings(true); // Overwrite existing
|
* const result = await migrateSettings();
|
||||||
* if (result.success) {
|
* if (result.success) {
|
||||||
* console.log(`Successfully migrated ${result.settingsMigrated} settings`);
|
* console.log(`Successfully migrated ${result.settingsMigrated} settings`);
|
||||||
* } else {
|
* } else {
|
||||||
@@ -1008,12 +1013,8 @@ export async function migrateContacts(
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
export async function migrateSettings(
|
export async function migrateSettings(): Promise<MigrationResult> {
|
||||||
overwriteExisting: boolean = false,
|
logger.info("[MigrationService] Starting settings migration");
|
||||||
): Promise<MigrationResult> {
|
|
||||||
logger.info("[MigrationService] Starting settings migration", {
|
|
||||||
overwriteExisting,
|
|
||||||
});
|
|
||||||
|
|
||||||
const result: MigrationResult = {
|
const result: MigrationResult = {
|
||||||
success: true,
|
success: true,
|
||||||
@@ -1026,19 +1027,34 @@ export async function migrateSettings(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const dexieSettings = await getDexieSettings();
|
const dexieSettings = await getDexieSettings();
|
||||||
|
logger.info("[MigrationService] Migrating settings", {
|
||||||
|
dexieSettings: dexieSettings.length,
|
||||||
|
});
|
||||||
const platformService = PlatformServiceFactory.getInstance();
|
const platformService = PlatformServiceFactory.getInstance();
|
||||||
// loop through dexieSettings,
|
|
||||||
// load the one with the matching accountDid from sqlite,
|
// Create an array of promises for all settings migrations
|
||||||
// and if one doesn't exist then insert it,
|
const migrationPromises = dexieSettings.map(async (setting) => {
|
||||||
// otherwise, update the fields
|
logger.info("[MigrationService] Starting to migrate settings", setting);
|
||||||
dexieSettings.forEach(async (setting) => {
|
let sqliteSettingRaw: { columns: string[], values: unknown[][] } | undefined;
|
||||||
const sqliteSettingRaw = await platformService.dbQuery(
|
if (!setting.accountDid) {
|
||||||
"SELECT * FROM settings WHERE accountDid = ?",
|
sqliteSettingRaw = await platformService.dbQuery(
|
||||||
[setting.accountDid]
|
"SELECT * FROM settings WHERE accountDid is null"
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
sqliteSettingRaw = await platformService.dbQuery(
|
||||||
|
"SELECT * FROM settings WHERE accountDid = ?",
|
||||||
|
[setting.accountDid]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
logger.info("[MigrationService] Migrating one set of settings:", {
|
||||||
|
setting,
|
||||||
|
sqliteSettingRaw,
|
||||||
|
});
|
||||||
if (sqliteSettingRaw?.values?.length) {
|
if (sqliteSettingRaw?.values?.length) {
|
||||||
// should cover the master settings, were accountDid is null
|
// should cover the master settings, were accountDid is null
|
||||||
const sqliteSetting = mapColumnsToValues(sqliteSettingRaw.columns, sqliteSettingRaw.values) as unknown as Settings;
|
const sqliteSettings = mapColumnsToValues(sqliteSettingRaw.columns, sqliteSettingRaw.values) as unknown as Settings[];
|
||||||
|
const sqliteSetting = sqliteSettings[0];
|
||||||
|
console.log('sqliteSetting', sqliteSetting)
|
||||||
let conditional: string;
|
let conditional: string;
|
||||||
let preparams: unknown[];
|
let preparams: unknown[];
|
||||||
if (!setting.accountDid) {
|
if (!setting.accountDid) {
|
||||||
@@ -1054,7 +1070,7 @@ export async function migrateSettings(
|
|||||||
conditional,
|
conditional,
|
||||||
preparams
|
preparams
|
||||||
);
|
);
|
||||||
await platformService.dbExec(sql, params);
|
await platformService.dbExec(sql, params)
|
||||||
result.settingsMigrated++;
|
result.settingsMigrated++;
|
||||||
} else {
|
} else {
|
||||||
// insert new setting
|
// insert new setting
|
||||||
@@ -1068,12 +1084,17 @@ export async function migrateSettings(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Wait for all migrations to complete
|
||||||
|
const updatedSettings = await Promise.all(migrationPromises);
|
||||||
|
|
||||||
|
logger.info("[MigrationService] Finished migrating settings", updatedSettings, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
logger.error("[MigrationService] Complete settings migration failed:", error);
|
||||||
const errorMessage = `Settings migration failed: ${error}`;
|
const errorMessage = `Settings migration failed: ${error}`;
|
||||||
result.errors.push(errorMessage);
|
result.errors.push(errorMessage);
|
||||||
result.success = false;
|
result.success = false;
|
||||||
logger.error("[MigrationService] Complete settings migration failed:", error);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1083,7 +1104,7 @@ export async function migrateSettings(
|
|||||||
*
|
*
|
||||||
* This function transfers all accounts from the Dexie database to the
|
* This function transfers all accounts from the Dexie database to the
|
||||||
* SQLite database. It handles both new accounts (INSERT) and existing
|
* SQLite database. It handles both new accounts (INSERT) and existing
|
||||||
* accounts (UPDATE) based on the overwriteExisting parameter.
|
* accounts (UPDATE).
|
||||||
*
|
*
|
||||||
* For accounts with mnemonic data, the function uses importFromMnemonic
|
* For accounts with mnemonic data, the function uses importFromMnemonic
|
||||||
* to ensure proper key derivation and identity creation during migration.
|
* to ensure proper key derivation and identity creation during migration.
|
||||||
@@ -1100,7 +1121,7 @@ export async function migrateSettings(
|
|||||||
* @example
|
* @example
|
||||||
* ```typescript
|
* ```typescript
|
||||||
* try {
|
* try {
|
||||||
* const result = await migrateAccounts(true); // Overwrite existing
|
* const result = await migrateAccounts();
|
||||||
* if (result.success) {
|
* if (result.success) {
|
||||||
* console.log(`Successfully migrated ${result.accountsMigrated} accounts`);
|
* console.log(`Successfully migrated ${result.accountsMigrated} accounts`);
|
||||||
* } else {
|
* } else {
|
||||||
@@ -1199,12 +1220,9 @@ export async function migrateAccounts(): Promise<MigrationResult> {
|
|||||||
* The migration runs within a transaction to ensure atomicity. If any step fails,
|
* The migration runs within a transaction to ensure atomicity. If any step fails,
|
||||||
* the entire migration is rolled back.
|
* the entire migration is rolled back.
|
||||||
*
|
*
|
||||||
* @param overwriteExisting - Whether to overwrite existing records in SQLite
|
|
||||||
* @returns Promise<MigrationResult> - Detailed result of the migration operation
|
* @returns Promise<MigrationResult> - Detailed result of the migration operation
|
||||||
*/
|
*/
|
||||||
export async function migrateAll(
|
export async function migrateAll(): Promise<MigrationResult> {
|
||||||
overwriteExisting: boolean = false,
|
|
||||||
): Promise<MigrationResult> {
|
|
||||||
const result: MigrationResult = {
|
const result: MigrationResult = {
|
||||||
success: false,
|
success: false,
|
||||||
contactsMigrated: 0,
|
contactsMigrated: 0,
|
||||||
@@ -1233,7 +1251,7 @@ export async function migrateAll(
|
|||||||
|
|
||||||
// Step 2: Migrate Settings (depends on accounts)
|
// Step 2: Migrate Settings (depends on accounts)
|
||||||
logger.info("[MigrationService] Step 2: Migrating settings...");
|
logger.info("[MigrationService] Step 2: Migrating settings...");
|
||||||
const settingsResult = await migrateSettings(overwriteExisting);
|
const settingsResult = await migrateSettings();
|
||||||
if (!settingsResult.success) {
|
if (!settingsResult.success) {
|
||||||
result.errors.push(
|
result.errors.push(
|
||||||
`Settings migration failed: ${settingsResult.errors.join(", ")}`,
|
`Settings migration failed: ${settingsResult.errors.join(", ")}`,
|
||||||
@@ -1244,16 +1262,17 @@ export async function migrateAll(
|
|||||||
result.warnings.push(...settingsResult.warnings);
|
result.warnings.push(...settingsResult.warnings);
|
||||||
|
|
||||||
// Step 3: Migrate Contacts (independent, but after accounts for consistency)
|
// Step 3: Migrate Contacts (independent, but after accounts for consistency)
|
||||||
logger.info("[MigrationService] Step 3: Migrating contacts...");
|
// ... but which is better done through the contact import view
|
||||||
const contactsResult = await migrateContacts(overwriteExisting);
|
// logger.info("[MigrationService] Step 3: Migrating contacts...");
|
||||||
if (!contactsResult.success) {
|
// const contactsResult = await migrateContacts();
|
||||||
result.errors.push(
|
// if (!contactsResult.success) {
|
||||||
`Contact migration failed: ${contactsResult.errors.join(", ")}`,
|
// result.errors.push(
|
||||||
);
|
// `Contact migration failed: ${contactsResult.errors.join(", ")}`,
|
||||||
return result;
|
// );
|
||||||
}
|
// return result;
|
||||||
result.contactsMigrated = contactsResult.contactsMigrated;
|
// }
|
||||||
result.warnings.push(...contactsResult.warnings);
|
// result.contactsMigrated = contactsResult.contactsMigrated;
|
||||||
|
// result.warnings.push(...contactsResult.warnings);
|
||||||
|
|
||||||
// All migrations successful
|
// All migrations successful
|
||||||
result.success = true;
|
result.success = true;
|
||||||
|
|||||||
@@ -19,8 +19,9 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Migration Options -->
|
||||||
|
<!--
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<!-- Migration Options -->
|
|
||||||
<div class="bg-white shadow rounded-lg">
|
<div class="bg-white shadow rounded-lg">
|
||||||
<div class="px-4 py-5 sm:p-6">
|
<div class="px-4 py-5 sm:p-6">
|
||||||
<h3 class="text-lg leading-6 font-medium text-gray-900 mb-4">
|
<h3 class="text-lg leading-6 font-medium text-gray-900 mb-4">
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="text-lg leading-6 font-medium text-red-900 mt-4"
|
class="text-lg leading-6 font-medium text-red-900 mt-4"
|
||||||
@@ -59,7 +61,7 @@
|
|||||||
<p
|
<p
|
||||||
v-if="comparison && (comparison.sqliteAccounts.length > 1 || comparison.sqliteSettings.length > 1 || comparison.sqliteContacts.length > 0)"
|
v-if="comparison && (comparison.sqliteAccounts.length > 1 || comparison.sqliteSettings.length > 1 || comparison.sqliteContacts.length > 0)"
|
||||||
>
|
>
|
||||||
Beware: you have unexpected existing data in the SQLite database that will be overwritten. Talk with Trent.
|
Beware: you have unexpected existing data in the new database that will be overwritten. Talk with Trent.
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p
|
||||||
v-if="cannotfindMainAccount"
|
v-if="cannotfindMainAccount"
|
||||||
@@ -951,7 +953,6 @@ import { Router } from "vue-router";
|
|||||||
import IconRenderer from "../components/IconRenderer.vue";
|
import IconRenderer from "../components/IconRenderer.vue";
|
||||||
import {
|
import {
|
||||||
compareDatabases,
|
compareDatabases,
|
||||||
migrateContacts,
|
|
||||||
migrateSettings,
|
migrateSettings,
|
||||||
migrateAccounts,
|
migrateAccounts,
|
||||||
migrateAll,
|
migrateAll,
|
||||||
@@ -1004,7 +1005,6 @@ export default class DatabaseMigration extends Vue {
|
|||||||
private loadingMessage = "";
|
private loadingMessage = "";
|
||||||
private error = "";
|
private error = "";
|
||||||
private exportedData: Record<string, any> | null = null;
|
private exportedData: Record<string, any> | null = null;
|
||||||
private overwriteExisting = true;
|
|
||||||
private successMessage = "";
|
private successMessage = "";
|
||||||
|
|
||||||
useClipboard = useClipboard;
|
useClipboard = useClipboard;
|
||||||
@@ -1075,7 +1075,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
window.alert('Copied to clipboard!');
|
window.alert('Copied to clipboard!');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to copy to clipboard:', error);
|
logger.error('Failed to copy to clipboard:', error);
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
window.alert('Failed to copy to clipboard');
|
window.alert('Failed to copy to clipboard');
|
||||||
}
|
}
|
||||||
@@ -1141,7 +1141,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
this.clearMessages();
|
this.clearMessages();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result: MigrationResult = await migrateAll(this.overwriteExisting);
|
const result: MigrationResult = await migrateAll();
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
const totalMigrated =
|
const totalMigrated =
|
||||||
@@ -1209,8 +1209,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
/**
|
/**
|
||||||
* Migrates contacts from Dexie to SQLite database
|
* Migrates contacts from Dexie to SQLite database
|
||||||
*
|
*
|
||||||
* This method transfers contacts from the Dexie database to SQLite,
|
* This method transfers contacts from the Dexie database to SQLite.
|
||||||
* with options to overwrite existing records.
|
|
||||||
*
|
*
|
||||||
* @async
|
* @async
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
@@ -1230,8 +1229,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
/**
|
/**
|
||||||
* Migrates settings from Dexie to SQLite database
|
* Migrates settings from Dexie to SQLite database
|
||||||
*
|
*
|
||||||
* This method transfers settings from the Dexie database to SQLite,
|
* This method transfers settings from the Dexie database to SQLite.
|
||||||
* with options to overwrite existing records.
|
|
||||||
*
|
*
|
||||||
* @async
|
* @async
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
@@ -1241,9 +1239,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
this.clearMessages();
|
this.clearMessages();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result: MigrationResult = await migrateSettings(
|
const result: MigrationResult = await migrateSettings();
|
||||||
this.overwriteExisting,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
this.successMessage = `Successfully migrated ${result.settingsMigrated} settings.`;
|
this.successMessage = `Successfully migrated ${result.settingsMigrated} settings.`;
|
||||||
@@ -1276,8 +1272,7 @@ export default class DatabaseMigration extends Vue {
|
|||||||
* Migrates accounts from Dexie to SQLite database
|
* Migrates accounts from Dexie to SQLite database
|
||||||
*
|
*
|
||||||
* This method transfers accounts from the Dexie database to SQLite,
|
* This method transfers accounts from the Dexie database to SQLite,
|
||||||
* with options to overwrite existing records. For accounts with mnemonic
|
* For accounts with mnemonic data, it uses the importFromMnemonic utility for proper key derivation.
|
||||||
* data, it uses the importFromMnemonic utility for proper key derivation.
|
|
||||||
*
|
*
|
||||||
* @async
|
* @async
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
|
|||||||
Reference in New Issue
Block a user