|
| 1 | +/** |
| 2 | + * Example: Exporting and downloading SQLite database |
| 3 | + * |
| 4 | + * This demonstrates how to export the database and download it in a browser |
| 5 | + */ |
| 6 | + |
| 7 | +import { |
| 8 | + SchemaBuilder, |
| 9 | + DeclarativeDatabase, |
| 10 | + AdapterFactory, |
| 11 | + StorageBackend, |
| 12 | +} from '../index'; |
| 13 | + |
| 14 | +const schema = new SchemaBuilder() |
| 15 | + .table('users', t => { |
| 16 | + t.guid('id').notNull(''); |
| 17 | + t.text('name').notNull(''); |
| 18 | + t.text('email').notNull(''); |
| 19 | + t.key('id').primary(); |
| 20 | + }) |
| 21 | + .build(); |
| 22 | + |
| 23 | +/** |
| 24 | + * Export database to a file (browser download) |
| 25 | + */ |
| 26 | +export async function exportDatabaseToDownload() { |
| 27 | + // Create and populate database |
| 28 | + const adapter = await AdapterFactory.create({ |
| 29 | + backend: StorageBackend.Memory, |
| 30 | + name: 'myapp.db', |
| 31 | + }); |
| 32 | + |
| 33 | + const db = new DeclarativeDatabase({ adapter, schema, autoMigrate: true }); |
| 34 | + await db.initialize(); |
| 35 | + |
| 36 | + // Add some data |
| 37 | + await db.insert('users', { id: 'u1', name: 'Alice', email: 'alice@example.com' }); |
| 38 | + await db.insert('users', { id: 'u2', name: 'Bob', email: 'bob@example.com' }); |
| 39 | + |
| 40 | + // Export database |
| 41 | + const dbBytes = await db.exportDatabase(); |
| 42 | + console.log('Database size:', dbBytes.length, 'bytes'); |
| 43 | + |
| 44 | + // In browser: trigger download |
| 45 | + if (typeof window !== 'undefined') { |
| 46 | + const blob = new Blob([new Uint8Array(dbBytes)], { type: 'application/x-sqlite3' }); |
| 47 | + const url = URL.createObjectURL(blob); |
| 48 | + const a = document.createElement('a'); |
| 49 | + a.href = url; |
| 50 | + a.download = 'myapp.db'; |
| 51 | + a.click(); |
| 52 | + URL.revokeObjectURL(url); |
| 53 | + console.log('Database download triggered'); |
| 54 | + } |
| 55 | + |
| 56 | + await db.close(); |
| 57 | +} |
| 58 | + |
| 59 | +/** |
| 60 | + * Export database to file system (Node.js) |
| 61 | + */ |
| 62 | +export async function exportDatabaseToFile() { |
| 63 | + const adapter = await AdapterFactory.create({ |
| 64 | + backend: StorageBackend.Memory, |
| 65 | + name: 'myapp.db', |
| 66 | + }); |
| 67 | + |
| 68 | + const db = new DeclarativeDatabase({ adapter, schema, autoMigrate: true }); |
| 69 | + await db.initialize(); |
| 70 | + |
| 71 | + // Add some data |
| 72 | + await db.insert('users', { id: 'u1', name: 'Alice', email: 'alice@example.com' }); |
| 73 | + |
| 74 | + // Export database |
| 75 | + const dbBytes = await db.exportDatabase(); |
| 76 | + |
| 77 | + // In Node.js: write to file |
| 78 | + if (typeof process !== 'undefined' && process.versions?.node) { |
| 79 | + const fs = await import('fs/promises'); |
| 80 | + await fs.writeFile('exported-database.db', dbBytes); |
| 81 | + console.log('Database exported to exported-database.db'); |
| 82 | + } |
| 83 | + |
| 84 | + await db.close(); |
| 85 | +} |
| 86 | + |
| 87 | +/** |
| 88 | + * Create a backup of the database |
| 89 | + */ |
| 90 | +export async function createDatabaseBackup() { |
| 91 | + const adapter = await AdapterFactory.create({ |
| 92 | + backend: StorageBackend.Auto, |
| 93 | + name: 'myapp.db', |
| 94 | + }); |
| 95 | + |
| 96 | + const db = new DeclarativeDatabase({ adapter, schema, autoMigrate: true }); |
| 97 | + await db.initialize(); |
| 98 | + |
| 99 | + // Regular operations... |
| 100 | + await db.insert('users', { id: 'u1', name: 'Alice', email: 'alice@example.com' }); |
| 101 | + |
| 102 | + // Create backup |
| 103 | + const backup = await db.exportDatabase(); |
| 104 | + |
| 105 | + // Store backup (could be to IndexedDB, localStorage, server, etc.) |
| 106 | + if (typeof localStorage !== 'undefined') { |
| 107 | + // Convert to base64 for localStorage |
| 108 | + const base64 = btoa(String.fromCharCode(...backup)); |
| 109 | + localStorage.setItem('db-backup', base64); |
| 110 | + console.log('Backup stored in localStorage'); |
| 111 | + } |
| 112 | + |
| 113 | + await db.close(); |
| 114 | +} |
| 115 | + |
| 116 | +/** |
| 117 | + * Restore database from backup |
| 118 | + */ |
| 119 | +export async function restoreDatabaseFromBackup() { |
| 120 | + if (typeof localStorage === 'undefined') { |
| 121 | + console.log('localStorage not available'); |
| 122 | + return; |
| 123 | + } |
| 124 | + |
| 125 | + // Retrieve backup |
| 126 | + const base64 = localStorage.getItem('db-backup'); |
| 127 | + if (!base64) { |
| 128 | + console.log('No backup found'); |
| 129 | + return; |
| 130 | + } |
| 131 | + |
| 132 | + // Convert from base64 |
| 133 | + const binaryString = atob(base64); |
| 134 | + const bytes = new Uint8Array(binaryString.length); |
| 135 | + for (let i = 0; i < binaryString.length; i++) { |
| 136 | + bytes[i] = binaryString.charCodeAt(i); |
| 137 | + } |
| 138 | + |
| 139 | + // Note: To restore, you would need to use the database's import functionality |
| 140 | + // This varies by adapter - sqlite-wasm might support importing via constructor |
| 141 | + console.log('Backup data retrieved:', bytes.length, 'bytes'); |
| 142 | +} |
| 143 | + |
| 144 | +/** |
| 145 | + * Export database periodically (auto-backup) |
| 146 | + */ |
| 147 | +export async function setupAutoBackup(intervalMs: number = 60000) { |
| 148 | + const adapter = await AdapterFactory.create({ |
| 149 | + backend: StorageBackend.Auto, |
| 150 | + name: 'myapp.db', |
| 151 | + }); |
| 152 | + |
| 153 | + const db = new DeclarativeDatabase({ adapter, schema, autoMigrate: true }); |
| 154 | + await db.initialize(); |
| 155 | + |
| 156 | + // Setup periodic backup |
| 157 | + const backupInterval = setInterval(async () => { |
| 158 | + try { |
| 159 | + const backup = await db.exportDatabase(); |
| 160 | + const timestamp = new Date().toISOString(); |
| 161 | + |
| 162 | + // Store with timestamp |
| 163 | + if (typeof localStorage !== 'undefined') { |
| 164 | + const base64 = btoa(String.fromCharCode(...backup)); |
| 165 | + localStorage.setItem(`db-backup-${timestamp}`, base64); |
| 166 | + console.log(`Backup created at ${timestamp}`); |
| 167 | + |
| 168 | + // Keep only last 5 backups |
| 169 | + const keys = Object.keys(localStorage).filter(k => k.startsWith('db-backup-')); |
| 170 | + if (keys.length > 5) { |
| 171 | + keys.sort(); |
| 172 | + for (let i = 0; i < keys.length - 5; i++) { |
| 173 | + const key = keys[i]; |
| 174 | + if (key) localStorage.removeItem(key); |
| 175 | + } |
| 176 | + } |
| 177 | + } |
| 178 | + } catch (error) { |
| 179 | + console.error('Backup failed:', error); |
| 180 | + } |
| 181 | + }, intervalMs); |
| 182 | + |
| 183 | + // Return cleanup function |
| 184 | + return () => { |
| 185 | + clearInterval(backupInterval); |
| 186 | + db.close(); |
| 187 | + }; |
| 188 | +} |
| 189 | + |
| 190 | +/** |
| 191 | + * Compare two database exports |
| 192 | + */ |
| 193 | +export async function compareDatabases() { |
| 194 | + // Create two databases |
| 195 | + const adapter1 = await AdapterFactory.create({ backend: StorageBackend.Memory }); |
| 196 | + const db1 = new DeclarativeDatabase({ adapter: adapter1, schema, autoMigrate: true }); |
| 197 | + await db1.initialize(); |
| 198 | + await db1.insert('users', { id: 'u1', name: 'Alice', email: 'alice@example.com' }); |
| 199 | + |
| 200 | + const adapter2 = await AdapterFactory.create({ backend: StorageBackend.Memory }); |
| 201 | + const db2 = new DeclarativeDatabase({ adapter: adapter2, schema, autoMigrate: true }); |
| 202 | + await db2.initialize(); |
| 203 | + await db2.insert('users', { id: 'u1', name: 'Alice', email: 'alice@example.com' }); |
| 204 | + |
| 205 | + // Export both |
| 206 | + const export1 = await db1.exportDatabase(); |
| 207 | + const export2 = await db2.exportDatabase(); |
| 208 | + |
| 209 | + // Compare |
| 210 | + const areEqual = export1.length === export2.length && |
| 211 | + export1.every((byte, i) => byte === export2[i]); |
| 212 | + |
| 213 | + console.log('Databases are equal:', areEqual); |
| 214 | + console.log('Database 1 size:', export1.length); |
| 215 | + console.log('Database 2 size:', export2.length); |
| 216 | + |
| 217 | + await db1.close(); |
| 218 | + await db2.close(); |
| 219 | +} |
| 220 | + |
| 221 | +// Run examples if executed directly |
| 222 | +if (require.main === module) { |
| 223 | + (async () => { |
| 224 | + console.log('=== Database Export Examples ===\n'); |
| 225 | + |
| 226 | + await exportDatabaseToDownload(); |
| 227 | + await exportDatabaseToFile(); |
| 228 | + await createDatabaseBackup(); |
| 229 | + await compareDatabases(); |
| 230 | + |
| 231 | + console.log('\n=== Examples completed ==='); |
| 232 | + })().catch(console.error); |
| 233 | +} |
0 commit comments