Use Node SQLite libraries for backup verification, if available
Some checks failed
CI/CD Pipeline / Test on Node.js 16.x and ubuntu-latest (release) Successful in 1m37s
CI/CD Pipeline / Test on Node.js 18.x and ubuntu-latest (release) Successful in 43s
CI/CD Pipeline / Test on Node.js 20.x and ubuntu-latest (release) Successful in 45s
CI/CD Pipeline / Test on Node.js 22.x and ubuntu-latest (release) Successful in 50s
CI/CD Pipeline / Lint and Code Quality (release) Failing after 11s
CI/CD Pipeline / Security Scan (release) Failing after 11s
CI/CD Pipeline / Test on Node.js 16.x and windows-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 18.x and macos-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 18.x and windows-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 20.x and macos-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 20.x and windows-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 22.x and macos-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 22.x and windows-latest (release) Has been cancelled
CI/CD Pipeline / Publish to npm (release) Has been cancelled
CI/CD Pipeline / Auto-increment version on main (release) Has been cancelled
Some checks failed
CI/CD Pipeline / Test on Node.js 16.x and ubuntu-latest (release) Successful in 1m37s
CI/CD Pipeline / Test on Node.js 18.x and ubuntu-latest (release) Successful in 43s
CI/CD Pipeline / Test on Node.js 20.x and ubuntu-latest (release) Successful in 45s
CI/CD Pipeline / Test on Node.js 22.x and ubuntu-latest (release) Successful in 50s
CI/CD Pipeline / Lint and Code Quality (release) Failing after 11s
CI/CD Pipeline / Security Scan (release) Failing after 11s
CI/CD Pipeline / Test on Node.js 16.x and windows-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 18.x and macos-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 18.x and windows-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 20.x and macos-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 20.x and windows-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 22.x and macos-latest (release) Has been cancelled
CI/CD Pipeline / Test on Node.js 22.x and windows-latest (release) Has been cancelled
CI/CD Pipeline / Publish to npm (release) Has been cancelled
CI/CD Pipeline / Auto-increment version on main (release) Has been cancelled
This commit is contained in:
parent
b34e4b5d83
commit
c2b4a8eca3
82
lib/index.js
82
lib/index.js
@ -1,7 +1,7 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { spawn, exec } = require('child_process');
|
||||
const { promisify } = require('util');
|
||||
const {spawn, exec} = require('child_process');
|
||||
const {promisify} = require('util');
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
/**
|
||||
@ -24,8 +24,8 @@ class SQLiteBackup {
|
||||
|
||||
this.databasePath = path.resolve(options.databasePath);
|
||||
this.backupDirectory = options.backupDirectory ?
|
||||
path.resolve(options.backupDirectory) :
|
||||
path.join(path.dirname(this.databasePath), 'backups');
|
||||
path.resolve(options.backupDirectory) :
|
||||
path.join(path.dirname(this.databasePath), 'backups');
|
||||
this.createBackupDir = options.createBackupDir !== false;
|
||||
|
||||
// Validate database file exists
|
||||
@ -35,8 +35,8 @@ class SQLiteBackup {
|
||||
|
||||
// Create backup directory if needed
|
||||
if (this.createBackupDir && !fs.existsSync(this.backupDirectory)) {
|
||||
fs.mkdirSync(this.backupDirectory, { recursive: true });
|
||||
}
|
||||
fs.mkdirSync(this.backupDirectory, {recursive: true});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,7 +99,7 @@ class SQLiteBackup {
|
||||
error: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -114,9 +114,27 @@ class SQLiteBackup {
|
||||
return false;
|
||||
}
|
||||
|
||||
const command = `sqlite3 "${backupPath}" "PRAGMA integrity_check;"`;
|
||||
const { stdout } = await execAsync(command);
|
||||
return stdout.trim() === 'ok';
|
||||
const dbDriver = this._getDatabaseDriver();
|
||||
|
||||
var result = "";
|
||||
|
||||
switch (dbDriver.type) {
|
||||
case "cli":
|
||||
const command = `sqlite3 "${backupPath}" "PRAGMA integrity_check;"`;
|
||||
const {stdout} = await execAsync(command);
|
||||
result = stdout.trim();
|
||||
break;
|
||||
case "better-sqlite3":
|
||||
const db = dbDriver.driver(backupPath);
|
||||
result = await db.pragma('integrity_check', {simple: true});
|
||||
break;
|
||||
case "sqlite3":
|
||||
result = await this._validateUsingSQLite3Package(dbDriver.driver, backupPath);
|
||||
console.log(result);
|
||||
break;
|
||||
}
|
||||
|
||||
return result === 'ok';
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
@ -182,7 +200,7 @@ class SQLiteBackup {
|
||||
removed: 0,
|
||||
errors: [error.message]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -212,7 +230,6 @@ class SQLiteBackup {
|
||||
isValid: null,
|
||||
checksum: null
|
||||
};
|
||||
|
||||
if (includeChecksums) {
|
||||
backup.checksum = await this._calculateChecksum(file.path);
|
||||
backup.isValid = await this.verifyBackup(file.path);
|
||||
@ -228,7 +245,7 @@ class SQLiteBackup {
|
||||
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to list backups: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,7 +312,7 @@ class SQLiteBackup {
|
||||
error: error.message,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Private methods
|
||||
@ -307,7 +324,7 @@ class SQLiteBackup {
|
||||
|
||||
const baseName = path.basename(this.databasePath, '.db');
|
||||
const timestamp = includeTimestamp ?
|
||||
`-${new Date().toISOString().replace(/[:.]/g, '-')}` : '';
|
||||
`-${new Date().toISOString().replace(/[:.]/g, '-')}` : '';
|
||||
|
||||
return `${baseName}-backup${timestamp}.db`;
|
||||
}
|
||||
@ -390,6 +407,25 @@ class SQLiteBackup {
|
||||
});
|
||||
}
|
||||
|
||||
async _validateUsingSQLite3Package(driver, databasePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const db = new driver.Database(databasePath, driver.OPEN_READONLY, err => {
|
||||
if (err) {
|
||||
return resolve("fail");
|
||||
}
|
||||
});
|
||||
|
||||
db.get("PRAGMA integrity_check", function (err, res) {
|
||||
console.log(res);
|
||||
if (typeof res == 'undefined') {
|
||||
resolve("fail");
|
||||
} else {
|
||||
resolve(res.integrity_check ?? "fail");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async _backupUsingCopy(backupPath) {
|
||||
fs.copyFileSync(this.databasePath, backupPath);
|
||||
}
|
||||
@ -401,7 +437,7 @@ class SQLiteBackup {
|
||||
|
||||
async _calculateChecksum(filePath) {
|
||||
try {
|
||||
const { stdout } = await execAsync(`shasum -a 256 "${filePath}"`);
|
||||
const {stdout} = await execAsync(`shasum -a 256 "${filePath}"`);
|
||||
return stdout.split(' ')[0];
|
||||
} catch (error) {
|
||||
return null;
|
||||
@ -434,7 +470,8 @@ class SQLiteBackup {
|
||||
|
||||
_matchesPattern(filename, pattern) {
|
||||
// Simple pattern matching - could be enhanced with a proper glob library
|
||||
if (pattern === '*' || pattern === '*.*') return true;
|
||||
if (pattern === '*' || pattern === '*.*')
|
||||
return true;
|
||||
if (pattern.startsWith('*.')) {
|
||||
const extension = pattern.slice(2);
|
||||
return filename.endsWith('.' + extension);
|
||||
@ -454,7 +491,8 @@ class BackupUtils {
|
||||
*/
|
||||
static formatSize(bytes) {
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
if (bytes === 0) return '0 B';
|
||||
if (bytes === 0)
|
||||
return '0 B';
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
return `${(bytes / Math.pow(1024, i)).toFixed(2)} ${sizes[i]}`;
|
||||
}
|
||||
@ -465,8 +503,10 @@ class BackupUtils {
|
||||
* @returns {string} Formatted duration string
|
||||
*/
|
||||
static formatDuration(milliseconds) {
|
||||
if (milliseconds < 1000) return `${milliseconds}ms`;
|
||||
if (milliseconds < 60000) return `${(milliseconds / 1000).toFixed(2)}s`;
|
||||
if (milliseconds < 1000)
|
||||
return `${milliseconds}ms`;
|
||||
if (milliseconds < 60000)
|
||||
return `${(milliseconds / 1000).toFixed(2)}s`;
|
||||
return `${(milliseconds / 60000).toFixed(2)}m`;
|
||||
}
|
||||
|
||||
@ -483,7 +523,7 @@ class BackupUtils {
|
||||
}
|
||||
|
||||
const command = `sqlite3 "${databasePath}" "PRAGMA integrity_check;"`;
|
||||
const { stdout } = await execAsync(command);
|
||||
const {stdout} = await execAsync(command);
|
||||
return stdout.trim() === 'ok';
|
||||
} catch (error) {
|
||||
return false;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user