2018-04-02 21:25:20 -04:00
const log = require ( './log' ) ;
const dataDir = require ( './data_dir' ) ;
const fs = require ( 'fs' ) ;
const sqlite = require ( 'sqlite' ) ;
const resourceDir = require ( './resource_dir' ) ;
const appInfo = require ( './app_info' ) ;
const sql = require ( './sql' ) ;
2018-04-02 22:33:54 -04:00
const cls = require ( './cls' ) ;
2019-04-23 21:27:45 +02:00
const utils = require ( './utils' ) ;
2018-07-24 20:35:03 +02:00
const optionService = require ( './options' ) ;
const Option = require ( '../entities/option' ) ;
2019-02-24 12:24:28 +01:00
const ImportContext = require ( '../services/import_context' ) ;
2018-04-02 21:25:20 -04:00
async function createConnection ( ) {
return await sqlite . open ( dataDir . DOCUMENT _PATH , { Promise } ) ;
}
2019-04-02 19:42:41 +02:00
const dbConnection = new Promise ( async ( resolve , reject ) => {
// no need to create new connection now since DB stays the same all the time
const db = await createConnection ( ) ;
sql . setDbConnection ( db ) ;
resolve ( ) ;
} ) ;
2018-04-02 21:25:20 -04:00
let dbReadyResolve = null ;
2018-07-23 21:15:32 +02:00
const dbReady = new Promise ( async ( resolve , reject ) => {
2018-07-22 19:56:20 +02:00
dbReadyResolve = resolve ;
2018-04-02 21:25:20 -04:00
2019-04-02 19:42:41 +02:00
await dbConnection ;
2018-07-23 21:15:32 +02:00
2018-07-22 19:56:20 +02:00
initDbConnection ( ) ;
} ) ;
2018-04-02 21:25:20 -04:00
2018-07-24 08:12:36 +02:00
async function schemaExists ( ) {
const tableResults = await sql . getRows ( "SELECT name FROM sqlite_master WHERE type='table' AND name='options'" ) ;
2018-04-02 21:25:20 -04:00
2018-07-22 19:56:20 +02:00
return tableResults . length === 1 ;
}
2018-07-21 08:55:24 +02:00
2018-07-24 08:12:36 +02:00
async function isDbInitialized ( ) {
if ( ! await schemaExists ( ) ) {
return false ;
}
const initialized = await sql . getValue ( "SELECT value FROM options WHERE name = 'initialized'" ) ;
2018-07-24 20:35:03 +02:00
// !initialized may be removed in the future, required only for migration
return ! initialized || initialized === 'true' ;
2018-07-24 08:12:36 +02:00
}
2018-07-22 19:56:20 +02:00
async function initDbConnection ( ) {
await cls . init ( async ( ) => {
2018-07-22 22:21:16 +02:00
if ( ! await isDbInitialized ( ) ) {
2018-09-10 19:09:05 +02:00
log . info ( "DB not initialized, please visit setup page to see instructions on how to initialize Trilium." ) ;
2018-04-02 21:25:20 -04:00
2018-04-03 22:15:28 -04:00
return ;
2018-04-02 21:25:20 -04:00
}
2018-04-03 22:15:28 -04:00
2018-07-24 20:35:03 +02:00
await sql . execute ( "PRAGMA foreign_keys = ON" ) ;
2019-04-23 21:27:45 +02:00
const currentDbVersion = await getDbVersion ( ) ;
if ( currentDbVersion > appInfo . dbVersion ) {
log . error ( ` Current DB version ${ currentDbVersion } is newer than app db version ${ appInfo . dbVersion } which means that it was created by newer and incompatible version of Trilium. Upgrade to latest version of Trilium to resolve this issue. ` ) ;
utils . crash ( ) ;
}
2018-04-03 22:15:28 -04:00
if ( ! await isDbUpToDate ( ) ) {
2018-06-10 15:49:22 -04:00
// avoiding circular dependency
const migrationService = require ( './migration' ) ;
await migrationService . migrate ( ) ;
2018-04-03 22:15:28 -04:00
}
2018-07-22 19:56:20 +02:00
log . info ( "DB ready." ) ;
2018-07-23 21:15:32 +02:00
dbReadyResolve ( ) ;
2018-04-02 21:25:20 -04:00
} ) ;
2018-07-22 19:56:20 +02:00
}
2018-04-02 21:25:20 -04:00
2018-07-21 08:55:24 +02:00
async function createInitialDatabase ( username , password ) {
2018-07-23 21:15:32 +02:00
log . info ( "Creating initial database ..." ) ;
2018-04-02 22:33:54 -04:00
2018-07-24 08:12:36 +02:00
if ( await isDbInitialized ( ) ) {
throw new Error ( "DB is already initialized" ) ;
}
2018-04-02 22:33:54 -04:00
const schema = fs . readFileSync ( resourceDir . DB _INIT _DIR + '/schema.sql' , 'UTF-8' ) ;
2018-11-16 14:36:50 +01:00
const demoFile = fs . readFileSync ( resourceDir . DB _INIT _DIR + '/demo.tar' ) ;
2018-04-02 22:33:54 -04:00
2018-04-07 13:03:16 -04:00
await sql . transactional ( async ( ) => {
2018-04-02 22:33:54 -04:00
await sql . executeScript ( schema ) ;
2018-11-16 14:36:50 +01:00
const Note = require ( "../entities/note" ) ;
const Branch = require ( "../entities/branch" ) ;
const rootNote = await new Note ( {
noteId : 'root' ,
title : 'root' ,
type : 'text' ,
mime : 'text/html'
} ) . save ( ) ;
2019-03-26 22:24:04 +01:00
await rootNote . setContent ( '' ) ;
2019-02-20 23:07:57 +01:00
2018-11-16 14:36:50 +01:00
await new Branch ( {
branchId : 'root' ,
noteId : 'root' ,
parentNoteId : 'none' ,
isExpanded : true ,
notePosition : 0
} ) . save ( ) ;
2019-02-24 12:24:28 +01:00
const dummyImportContext = new ImportContext ( "1" , false ) ;
2018-11-16 14:36:50 +01:00
const tarImportService = require ( "./import/tar" ) ;
2019-02-24 12:24:28 +01:00
await tarImportService . importTar ( dummyImportContext , demoFile , rootNote ) ;
2018-04-02 22:33:54 -04:00
const startNoteId = await sql . getValue ( "SELECT noteId FROM branches WHERE parentNoteId = 'root' AND isDeleted = 0 ORDER BY notePosition" ) ;
2018-07-23 21:15:32 +02:00
const optionsInitService = require ( './options_init' ) ;
await optionsInitService . initDocumentOptions ( ) ;
await optionsInitService . initSyncedOptions ( username , password ) ;
2018-07-24 08:12:36 +02:00
await optionsInitService . initNotSyncedOptions ( true , startNoteId ) ;
2018-07-23 21:15:32 +02:00
2018-04-02 22:33:54 -04:00
await require ( './sync_table' ) . fillAllSyncRows ( ) ;
} ) ;
2018-07-23 21:15:32 +02:00
log . info ( "Schema and initial content generated." ) ;
2018-04-02 22:33:54 -04:00
2018-07-22 19:56:20 +02:00
await initDbConnection ( ) ;
2018-04-02 21:25:20 -04:00
}
2018-07-25 08:30:41 +02:00
async function createDatabaseForSync ( options , syncServerHost = '' , syncProxy = '' ) {
2018-07-24 20:35:03 +02:00
log . info ( "Creating database for sync" ) ;
if ( await isDbInitialized ( ) ) {
throw new Error ( "DB is already initialized" ) ;
}
2018-07-23 21:15:32 +02:00
const schema = fs . readFileSync ( resourceDir . DB _INIT _DIR + '/schema.sql' , 'UTF-8' ) ;
await sql . transactional ( async ( ) => {
await sql . executeScript ( schema ) ;
2018-08-17 18:11:03 +02:00
await require ( './options_init' ) . initNotSyncedOptions ( false , 'root' , syncServerHost , syncProxy ) ;
2018-07-24 20:35:03 +02:00
// document options required for sync to kick off
for ( const opt of options ) {
await new Option ( opt ) . save ( ) ;
}
2018-07-23 21:15:32 +02:00
} ) ;
log . info ( "Schema and not synced options generated." ) ;
}
2019-04-23 21:27:45 +02:00
async function getDbVersion ( ) {
return parseInt ( await sql . getValue ( "SELECT value FROM options WHERE name = 'dbVersion'" ) ) ;
}
2018-04-02 21:25:20 -04:00
async function isDbUpToDate ( ) {
2019-04-23 21:27:45 +02:00
const dbVersion = await getDbVersion ( ) ;
2018-04-02 21:25:20 -04:00
2018-04-02 21:47:46 -04:00
const upToDate = dbVersion >= appInfo . dbVersion ;
2018-04-02 21:25:20 -04:00
if ( ! upToDate ) {
2018-04-02 21:47:46 -04:00
log . info ( "App db version is " + appInfo . dbVersion + ", while db version is " + dbVersion + ". Migration needed." ) ;
2018-04-02 21:25:20 -04:00
}
return upToDate ;
}
2018-07-24 20:35:03 +02:00
async function dbInitialized ( ) {
await optionService . setOption ( 'initialized' , 'true' ) ;
await initDbConnection ( ) ;
}
2019-01-15 20:00:24 +01:00
dbReady . then ( async ( ) => {
log . info ( "DB size: " + await sql . getValue ( "SELECT page_count * page_size / 1000 as size FROM pragma_page_count(), pragma_page_size()" ) + " KB" ) ;
} ) ;
2018-04-02 21:25:20 -04:00
module . exports = {
dbReady ,
2019-04-02 19:42:41 +02:00
dbConnection ,
2018-07-24 08:12:36 +02:00
schemaExists ,
2018-07-22 19:56:20 +02:00
isDbInitialized ,
initDbConnection ,
2018-07-21 08:55:24 +02:00
isDbUpToDate ,
2018-07-23 21:15:32 +02:00
createInitialDatabase ,
2018-07-24 20:35:03 +02:00
createDatabaseForSync ,
dbInitialized
2018-04-02 21:25:20 -04:00
} ;