From e02e0d97e0e3eaa6b7c46854d98bc227fba8a78f Mon Sep 17 00:00:00 2001 From: Xymorot Date: Tue, 10 Dec 2019 23:33:48 +0100 Subject: [PATCH] feat: use userData electron path for database (subfolder with version) This has the side effect of no more ormconfig.yml file, and the database connections are now only loaded on demand (as well as running the migrations). BREAKING CHANGE: there is no migration for the old database --- .gitignore | 3 +-- forge.config.js | 3 +-- mocks/electron.ts | 17 ++++++++----- mocks/tslint.json | 6 ----- ormconfig.yml | 9 ------- package.json | 5 ++-- src/main.ts | 16 +++++++++---- src/main/services/database.ts | 36 +++++++++++++++++++++------- tests/main/services/database.spec.ts | 21 ++++++++++++++++ 9 files changed, 75 insertions(+), 41 deletions(-) delete mode 100644 mocks/tslint.json delete mode 100644 ormconfig.yml create mode 100644 tests/main/services/database.spec.ts diff --git a/.gitignore b/.gitignore index 146d798..4bae92d 100644 --- a/.gitignore +++ b/.gitignore @@ -15,10 +15,9 @@ node_modules # created by testing /store-backup -/database-backup +/test-paths # managed by application -/database /store # built app diff --git a/forge.config.js b/forge.config.js index 51ce28d..7358592 100644 --- a/forge.config.js +++ b/forge.config.js @@ -3,13 +3,12 @@ const ignoreList = [ /^\/\.vscode($|\/)/, /^\/\.nyc_output($|\/)/, - /^\/database($|\/)/, - /^\/database-backup($|\/)/, /^\/declarations($|\/)/, /^\/mocks($|\/)/, /^\/store($|\/)/, /^\/store-backup($|\/)/, /^\/templates($|\/)/, + /^\/test-paths($|\/)/, /^\/tests($|\/)/, /^\/workspace($|\/)/, diff --git a/mocks/electron.ts b/mocks/electron.ts index 949a028..3963874 100644 --- a/mocks/electron.ts +++ b/mocks/electron.ts @@ -1,19 +1,24 @@ -import { rewiremock } from './rewiremock'; import WebContents = Electron.WebContents; +import path from 'path'; +import { rewiremock } from './rewiremock'; const electronMock: DeepPartial = { app: { - on() {}, + on(): void {}, + getPath(name: string): string { + return path.resolve('test-paths', name); + }, + quit(): void {}, }, BrowserWindow: class { public webContents: DeepPartial = { - openDevTools() {}, + openDevTools(): void {}, }; - public loadFile() {} - public on() {} + public loadFile(): void {} + public on(): void {} }, ipcMain: { - on() {}, + on(): void {}, }, }; diff --git a/mocks/tslint.json b/mocks/tslint.json deleted file mode 100644 index a657d99..0000000 --- a/mocks/tslint.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["../tslint.json"], - "rules": { - "typedef": false - } -} diff --git a/ormconfig.yml b/ormconfig.yml deleted file mode 100644 index 084ca43..0000000 --- a/ormconfig.yml +++ /dev/null @@ -1,9 +0,0 @@ -library: - type: sqlite - database: ./database/library.db - entities: - - ./src/main/entities/library/*.js - migrations: - - ./src/main/migrations/library/*.js - cli: - migrationsDir: ./src/main/migrations/library diff --git a/package.json b/package.json index fd5c01a..350f103 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "main": "src/main.js", "scripts": { "postinstall": "npm run rebuild", - "start": "electron . --enable-logging", + "start": "electron . --enable-logging --dev", "rebuild": "electron-rebuild -f -b -t prod,dev,optional", "typeorm:migrate": "npm run typeorm:migrate:library", "typeorm:migrate:library": "typeorm migration:run -c library", @@ -41,7 +41,6 @@ "prettier": "prettier --ignore-path .gitignore -c **/*.{html,handlebars,json,{c,sc,sa,le}ss,yml,svelte,md,ts,js}", "prettier:fix": "prettier --ignore-path .gitignore --write **/*.{html,handlebars,json,{c,sc,sa,le}ss,yml,svelte,md,ts,js}", "fix": "npm run lint:check && npm run lint:fix && npm run prettier:fix", - "forge:start": "electron-forge start", "forge:make": "electron-forge --platform win32 --arch x64 make", "forge": "npm run build && npm run forge:make", "precommit": "npm run build && npm run prettier && npm run lint:check && npm run lint && npm run coverage:fast", @@ -50,6 +49,7 @@ "dependencies": { "fs-extra": "^8.1.0", "jsdom": "^15.2.1", + "minimist": "^1.2.0", "node-fetch": "^2.6.0", "sqlite3": "^4.1.1", "typeorm": "^0.2.21", @@ -79,7 +79,6 @@ "handlebars": "^4.5.3", "husky": "^3.1.0", "lodash": "^4.17.15", - "minimist": "^1.2.0", "mocha": "^6.2.2", "nock": "^11.7.0", "nyc": "^14.1.1", diff --git a/src/main.ts b/src/main.ts index 4112a7c..2e74d54 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,13 +1,19 @@ import { app, BrowserWindow } from 'electron'; -import os from 'os'; - -import './main/controllers/api'; -import './main/services/database'; -import * as session from './main/services/session'; import BrowserWindowConstructorOptions = Electron.BrowserWindowConstructorOptions; +import minimist from 'minimist'; +import os from 'os'; +import path from 'path'; +import packageJson from '../package.json'; +import './main/controllers/api'; +import * as session from './main/services/session'; export let mainWindow: Electron.BrowserWindow; +export let appPath = path.resolve( + app.getPath('userData'), + `${packageJson.version}${minimist(process.argv).dev ? '-dev' : ''}` +); + async function createWindow(): Promise { session.setHeaders(); diff --git a/src/main/services/database.ts b/src/main/services/database.ts index a6b48aa..4851c3d 100644 --- a/src/main/services/database.ts +++ b/src/main/services/database.ts @@ -1,30 +1,50 @@ +import path from 'path'; import 'reflect-metadata'; -import { Connection, createConnection } from 'typeorm'; -import { throwError } from './error'; +import { Connection, createConnection as ormCreateConnection } from 'typeorm'; +import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'; +import { appPath } from '../../main'; export enum Databases { LIBRARY = 'library', } +type MyConnectionOptions = { [key in Databases]?: SqliteConnectionOptions }; + +const databasePath = path.resolve(appPath, 'database'); +const connectionOptions: MyConnectionOptions = Object.values(Databases).reduce( + (prev: MyConnectionOptions, database: Databases) => { + prev[database] = { + type: 'sqlite', + database: path.resolve(databasePath, `${database}.db`), + entities: [`./src/main/entities/${database}/*.js`], + migrations: [`./src/main/migrations/${database}/*.js`], + cli: { + migrationsDir: `./src/main/migrations/${database}`, + }, + }; + return prev; + }, + {} +); + const connections: { [key in Databases]?: Connection; } = {}; -Object.values(Databases).forEach((database: Databases) => { - createConnection(database) +function createConnection(database: Databases): Promise { + return ormCreateConnection(connectionOptions[database]) .then((connection: Connection) => { connections[database] = connection; return connection.runMigrations(); }) - .catch((reason: any) => { - throwError(reason, true); + .then(() => { + return connections[database]; }); -}); +} export function getConnection(database: Databases): Promise { if (connections[database] === undefined) { return createConnection(database).then((connection: Connection) => { - connections[database] = connection; return connection; }); } else { diff --git a/tests/main/services/database.spec.ts b/tests/main/services/database.spec.ts new file mode 100644 index 0000000..fe0cdf8 --- /dev/null +++ b/tests/main/services/database.spec.ts @@ -0,0 +1,21 @@ +import rewiremock from 'rewiremock'; +import '../../../mocks/electron'; + +import { expect } from 'chai'; +import 'mocha'; +import { Databases, getConnection } from '../../../src/main/services/database'; + +describe('Database Service', () => { + before(() => { + rewiremock.enable(); + }); + + after(() => { + rewiremock.disable(); + }); + + it('returns a connection', async () => { + const libraryConnection = await getConnection(Databases.LIBRARY); + expect(libraryConnection).to.not.equal(undefined); + }); +});