forked from trent_larson/crowd-funder-for-time-pwa
- Add contactsToExportJson utility function for standardized data export - Replace CSV export with JSON format in DataExportSection - Update file extension and MIME type to application/json - Remove Dexie-specific export logic in favor of unified SQLite/Dexie approach - Update success notifications to reflect JSON format - Add TypeScript interfaces for export data structure This change improves data portability and standardization by: - Using a consistent JSON format for data export/import - Supporting both SQLite and Dexie databases - Including all contact fields in export - Properly handling contactMethods as stringified JSON - Maintaining backward compatibility with existing import tools Security: No sensitive data exposure, maintains existing access controls
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
interface Migration {
|
|
name: string;
|
|
sql: string;
|
|
}
|
|
|
|
export class MigrationService {
|
|
private static instance: MigrationService;
|
|
private migrations: Migration[] = [];
|
|
|
|
private constructor() {}
|
|
|
|
static getInstance(): MigrationService {
|
|
if (!MigrationService.instance) {
|
|
MigrationService.instance = new MigrationService();
|
|
}
|
|
return MigrationService.instance;
|
|
}
|
|
|
|
registerMigration(migration: Migration) {
|
|
this.migrations.push(migration);
|
|
}
|
|
|
|
/**
|
|
* @param sqlExec - A function that executes a SQL statement and returns some update result
|
|
* @param sqlQuery - A function that executes a SQL query and returns the result in some format
|
|
* @param extractMigrationNames - A function that extracts the names (string array) from a "select name from migrations" query
|
|
*/
|
|
async runMigrations<T>(
|
|
// note that this does not take parameters because the Capacitor SQLite 'execute' is different
|
|
sqlExec: (sql: string) => Promise<unknown>,
|
|
sqlQuery: (sql: string) => Promise<T>,
|
|
extractMigrationNames: (result: T) => Set<string>,
|
|
): Promise<void> {
|
|
|
|
// Create migrations table if it doesn't exist
|
|
const result0 = await sqlExec(`
|
|
CREATE TABLE IF NOT EXISTS migrations (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL UNIQUE,
|
|
executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
`);
|
|
|
|
// Get list of executed migrations
|
|
const result1: T = await sqlQuery("SELECT name FROM migrations;");
|
|
const executedMigrations = extractMigrationNames(result1);
|
|
|
|
|
|
// Run pending migrations in order
|
|
for (const migration of this.migrations) {
|
|
if (!executedMigrations.has(migration.name)) {
|
|
await sqlExec(migration.sql);
|
|
|
|
await sqlExec(
|
|
`INSERT INTO migrations (name) VALUES ('${migration.name}')`,
|
|
);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export default MigrationService.getInstance();
|