diff --git a/src/JsonDB.ts b/src/JsonDB.ts index 1c7592a6..f9b00a91 100644 --- a/src/JsonDB.ts +++ b/src/JsonDB.ts @@ -24,13 +24,14 @@ export class JsonDB { * @param saveOnPush save the database at each push command into the json file * @param humanReadable the JSON file will be readable easily by a human * @param separator what to use as separator + * @param syncOnSave force sync of the database (call fsync()) */ - constructor(filename: string | Config, saveOnPush: boolean = true, humanReadable: boolean = false, separator: string = '/') { + constructor(filename: string | Config, saveOnPush: boolean = true, humanReadable: boolean = false, separator: string = '/', syncOnSave: boolean = false) { if(filename instanceof Config) { this.config = filename } else { - this.config = new Config(filename, saveOnPush, humanReadable, separator) + this.config = new Config(filename, saveOnPush, humanReadable, separator, syncOnSave) } if (!FS.existsSync(this.config.filename)) { @@ -363,7 +364,24 @@ export class JsonDB { else { data = JSON.stringify(this.data) } - FS.writeFileSync(this.config.filename, data, 'utf8') + if(this.config.syncOnSave) { + const buffer = Buffer.from(String(data), 'utf8') + const fd_tmp = FS.openSync(this.config.filename, 'w') + let offset = 0 + let length = buffer.byteLength + try { + while (length > 0) { + const written = FS.writeSync(fd_tmp, buffer, offset, length) + offset += written + length -= written + } + } finally { + FS.fsyncSync(fd_tmp) + FS.closeSync(fd_tmp) + } + } else { + FS.writeFileSync(this.config.filename, data, 'utf8') + } } catch (err) { const error = new DatabaseError("Can't save the database", 2, err) throw error diff --git a/src/lib/JsonDBConfig.ts b/src/lib/JsonDBConfig.ts index 64b89dd5..00a80e92 100644 --- a/src/lib/JsonDBConfig.ts +++ b/src/lib/JsonDBConfig.ts @@ -4,7 +4,8 @@ export interface JsonDBConfig { filename: string, saveOnPush: boolean, humanReadable: boolean, - separator: string + separator: string, + syncOnSave: boolean } export class Config implements JsonDBConfig { @@ -12,9 +13,9 @@ export class Config implements JsonDBConfig { humanReadable: boolean saveOnPush: boolean separator: string + syncOnSave: boolean - - constructor(filename: string, saveOnPush: boolean = true, humanReadable: boolean = false, separator: string = '/') { + constructor(filename: string, saveOnPush: boolean = true, humanReadable: boolean = false, separator: string = '/', syncOnSave: boolean = false) { this.filename = filename // Force json if no extension @@ -25,5 +26,6 @@ export class Config implements JsonDBConfig { this.humanReadable = humanReadable this.saveOnPush = saveOnPush this.separator = separator + this.syncOnSave = syncOnSave } } \ No newline at end of file diff --git a/test/02-jsondb.test.ts b/test/02-jsondb.test.ts index f53b7358..799a565e 100644 --- a/test/02-jsondb.test.ts +++ b/test/02-jsondb.test.ts @@ -10,6 +10,7 @@ const testFile3 = "test/test_file3" const testFile4 = "test/array_file" const testFile5 = "test/test_file_empty" const testFile6 = "test/test_delete" +const testFile7 = "test/test_sync" interface Test { @@ -56,6 +57,14 @@ describe('JsonDB', () => { }) + test('should create JSON file with sync', done => { + const jsondb = new JsonDB(testFile7, true, false, '/', true) + fs.access(testFile7+ ".json", fs.constants.R_OK, function (err) { + expect(err).toBeNull() + done() + }) + }) + test('should set en empty root', () => { expect(JSON.stringify(db.getData("/"))).toEqual("{}") }) @@ -652,6 +661,7 @@ describe('JsonDB', () => { fs.unlinkSync(testFile4 + ".json") fs.unlinkSync(testFile5 + ".json") fs.unlinkSync(testFile6 + ".json") + fs.unlinkSync(testFile7 + ".json") fs.rmdirSync("test/dirCreation") }) })