diff --git a/packages/electron/db.ts b/packages/electron/db.ts index 054cdb6..a138ba9 100644 --- a/packages/electron/db.ts +++ b/packages/electron/db.ts @@ -4,8 +4,9 @@ import fs from 'fs' import SQLite3 from 'better-sqlite3' import log from './log' import { createFileIfNotExist } from './utils' - -const isDev = process.env.NODE_ENV === 'development' +import pkg from '../../package.json' +import { compare, validate } from 'compare-versions' +import { dirname } from './utils' export const enum Tables { Track = 'Track', @@ -17,6 +18,7 @@ export const enum Tables { Audio = 'Audio', AccountData = 'AccountData', CoverColor = 'CoverColor', + AppData = 'AppData', } interface CommonTableStructure { id: number @@ -55,10 +57,18 @@ export interface TablesStructures { id: number color: string } + [Tables.AppData]: { + id: 'appVersion' | 'skippedVersion' + value: string + } } type TableNames = keyof TablesStructures +const readSqlFile = (filename: string) => { + return fs.readFileSync(path.join(dirname, `./migrations/${filename}`), 'utf8') +} + class DB { sqlite: SQLite3.Database dbFilePath: string = path.resolve( @@ -79,24 +89,48 @@ class DB { }) this.sqlite.pragma('auto_vacuum = FULL') this.initTables() + this.migrate() log.info('[db] Database initialized') } initTables() { - const migration = fs.readFileSync( - isDev - ? path.join(process.cwd(), './migrations/init.sql') - : path.join(__dirname, './migrations/init.sql'), - 'utf8' - ) - this.sqlite.exec(migration) + const init = readSqlFile('init.sql') + this.sqlite.exec(init) + } + + migrate() { + const key = 'appVersion' + const appVersion = this.find(Tables.AppData, key) + const updateAppVersionInDB = () => { + this.upsert(Tables.AppData, { + id: key, + value: pkg.version, + }) + } + + if (!appVersion?.value) { + updateAppVersionInDB() + return + } + + const sqlFiles = fs.readdirSync(path.join(dirname, './migrations')) + sqlFiles.forEach((sqlFile: string) => { + const version = sqlFile.split('.').shift() || '' + if (!validate(version)) return + if (compare(version, pkg.version, '>')) { + const file = readSqlFile(sqlFile) + this.sqlite.exec(file) + } + }) + + updateAppVersionInDB() } find( table: T, key: TablesStructures[T]['id'] - ): TablesStructures[T] { + ): TablesStructures[T] | undefined { return this.sqlite .prepare(`SELECT * FROM ${table} WHERE id = ? LIMIT 1`) .get(key) diff --git a/packages/electron/migrations/init.sql b/packages/electron/migrations/init.sql index f1bc92e..13e3cc7 100644 --- a/packages/electron/migrations/init.sql +++ b/packages/electron/migrations/init.sql @@ -7,3 +7,4 @@ CREATE TABLE IF NOT EXISTS "Lyric" ("id" integer NOT NULL,"json" text NOT NULL," CREATE TABLE IF NOT EXISTS "Playlist" ("id" integer NOT NULL,"json" text NOT NULL,"updatedAt" int NOT NULL, PRIMARY KEY (id)); CREATE TABLE IF NOT EXISTS "Track" ("id" integer NOT NULL,"json" text NOT NULL,"updatedAt" int NOT NULL, PRIMARY KEY (id)); CREATE TABLE IF NOT EXISTS "CoverColor" ("id" integer NOT NULL,"color" text NOT NULL, PRIMARY KEY (id)); +CREATE TABLE IF NOT EXISTS "AppData" ("id" text NOT NULL,"value" text, PRIMARY KEY (id)); diff --git a/packages/electron/package.json b/packages/electron/package.json index 4c0c042..be5f930 100644 --- a/packages/electron/package.json +++ b/packages/electron/package.json @@ -21,6 +21,7 @@ "NeteaseCloudMusicApi": "^4.5.12", "better-sqlite3": "7.5.1", "change-case": "^4.1.2", + "compare-versions": "^4.1.3", "cookie-parser": "^1.4.6", "electron-log": "^4.4.6", "electron-store": "^8.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f1fb6f2..34d73dd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,6 +30,7 @@ importers: axios: ^0.27.2 better-sqlite3: 7.5.1 change-case: ^4.1.2 + compare-versions: ^4.1.3 cookie-parser: ^1.4.6 cross-env: ^7.0.3 dotenv: ^16.0.0 @@ -61,6 +62,7 @@ importers: '@unblockneteasemusic/rust-napi': 0.3.0-pre.1 better-sqlite3: 7.5.1 change-case: 4.1.2 + compare-versions: 4.1.3 cookie-parser: 1.4.6 electron-log: 4.4.7 electron-store: 8.0.1 @@ -2554,6 +2556,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /compare-versions/4.1.3: + resolution: {integrity: sha512-WQfnbDcrYnGr55UwbxKiQKASnTtNnaAWVi8jZyy8NTpVAXWACSne8lMD1iaIo9AiU6mnuLvSVshCzewVuWxHUg==} + dev: false + /component-emitter/1.3.0: resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} dev: true