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
This commit is contained in:
Xymorot 2019-12-10 23:33:48 +01:00
parent 41fc16c1c8
commit e02e0d97e0
9 changed files with 75 additions and 41 deletions

3
.gitignore vendored
View File

@ -15,10 +15,9 @@ node_modules
# created by testing
/store-backup
/database-backup
/test-paths
# managed by application
/database
/store
# built app

View File

@ -3,13 +3,12 @@ const ignoreList = [
/^\/\.vscode($|\/)/,
/^\/\.nyc_output($|\/)/,
/^\/database($|\/)/,
/^\/database-backup($|\/)/,
/^\/declarations($|\/)/,
/^\/mocks($|\/)/,
/^\/store($|\/)/,
/^\/store-backup($|\/)/,
/^\/templates($|\/)/,
/^\/test-paths($|\/)/,
/^\/tests($|\/)/,
/^\/workspace($|\/)/,

View File

@ -1,19 +1,24 @@
import { rewiremock } from './rewiremock';
import WebContents = Electron.WebContents;
import path from 'path';
import { rewiremock } from './rewiremock';
const electronMock: DeepPartial<typeof Electron> = {
app: {
on() {},
on(): void {},
getPath(name: string): string {
return path.resolve('test-paths', name);
},
quit(): void {},
},
BrowserWindow: class {
public webContents: DeepPartial<WebContents> = {
openDevTools() {},
openDevTools(): void {},
};
public loadFile() {}
public on() {}
public loadFile(): void {}
public on(): void {}
},
ipcMain: {
on() {},
on(): void {},
},
};

View File

@ -1,6 +0,0 @@
{
"extends": ["../tslint.json"],
"rules": {
"typedef": false
}
}

View File

@ -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

View File

@ -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",

View File

@ -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<void> {
session.setHeaders();

View File

@ -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<Connection> {
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<Connection> {
if (connections[database] === undefined) {
return createConnection(database).then((connection: Connection) => {
connections[database] = connection;
return connection;
});
} else {

View File

@ -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);
});
});