Allow for nonexistent root item, make get() default value be written back
authorNick Downing <nick@ndcode.org>
Wed, 5 Jan 2022 01:21:36 +0000 (12:21 +1100)
committerNick Downing <nick@ndcode.org>
Wed, 5 Jan 2022 01:24:25 +0000 (12:24 +1100)
a.mjs
b.mjs
logjson.mjs

diff --git a/a.mjs b/a.mjs
index 4f546cf..2dec243 100755 (executable)
--- a/a.mjs
+++ b/a.mjs
@@ -4,7 +4,7 @@ import logjson from './logjson.mjs'
 import fsPromises from 'fs/promises'
 
 let file = new logjson.File()
-await file.open('a.logjson', {})
+await file.open('a.logjson')
 file.set(
   logjson.json_to_logjson(
     JSON.parse(await fsPromises.readFile('random.json', 'utf-8'))
diff --git a/b.mjs b/b.mjs
index 4ef7c24..7dfe99f 100755 (executable)
--- a/b.mjs
+++ b/b.mjs
@@ -4,7 +4,7 @@ import logjson from './logjson.mjs'
 import fsPromises from 'fs/promises'
 
 let file = new logjson.File()
-await file.open('a.logjson', {})
+await file.open('a.logjson')
 await fsPromises.writeFile(
   'a.json',
   Buffer.from(
index fd06592..e9c7b15 100644 (file)
@@ -9,10 +9,10 @@ class File {
     this.mutex = new Mutex()
     this.log = null
     this.eof = 0
-    this.value = [-1, 0]
+    this.value = undefined
   }
 
-  async open(path, default_value) {
+  async open(path) {
     await this.mutex.acquire()
     assert(this.log === null)
 
@@ -23,20 +23,40 @@ class File {
       if (error.code !== 'ENOENT')
         throw error
 
+      console.log('warning: can\'t find database file, creating')
+
       this.log = await fsPromises.open(path, 'w+')
       this.eof = 0
+      this.value = undefined
 
-      this.value = await this.write(default_value, true)
+      this.mutex.release()
       return
     }
 
     this.eof = (await this.log.stat()).size
-    this.value = await this.find_root()
+    try {
+      this.value = await this.find_root()
+    }
+    catch (error) {
+      console.log('warning: can\'t find root, truncating database file')
+
+      await this.log.truncate(0)
+      this.eof = 0
+      this.value = undefined
+
+      this.mutex.release()
+      return
+    }
 
     // optional: trim any garbage off the end of the file
     let [ptr, len] = this.value
-    this.eof = ptr + len + 2
-    await this.log.truncate(this.eof)
+    let eof = ptr + len + 2
+    if (eof < this.eof) {
+      console.log('warning: garbage after root, truncating database file')
+
+      await this.log.truncate(eof)
+      this.eof = eof
+    }
 
     this.mutex.release()
   }
@@ -108,51 +128,12 @@ class File {
     throw new Error('can\'t find logjson end marker')
   }
 
-  async write(value, is_root) {
-    if (typeof value === 'object' && value !== null)
-      if (value instanceof Array) {
-        let new_value = []
-        for (let i = 0; i < value.length; ++i) {
-          let item = value[i]
-          //if (typeof item === 'object' && item !== null)
-            item = await this.write(item, false)
-          new_value.push(item)
-        }
-        value = new_value
-      }
-      else {
-        let new_value = {}
-        for (let i in value) {
-          let item = value[i]
-          //if (typeof item === 'object' && item !== null)
-            item = await this.write(item, false)
-          new_value[i] = item
-        }
-        value = new_value
-      }
-
-    let data = JSON.stringify(value, null, 2)
-    if (is_root) {
-      let buffer = Buffer.from(`<${data}>\n`, 'utf-8')
-      let ptr = this.eof
-      let len = buffer.length
-      assert(
-        (await this.log.write(buffer, 0, len, ptr)).bytesWritten === len
-      )
-      this.eof += len
-      return [ptr + 1, len - 3] // ptr, len
+  async get(default_value) {
+    if (this.value === undefined) {
+      if (default_value === undefined)
+        return undefined
+      set(default_value)
     }
-    let buffer = Buffer.from(`${data}\n`, 'utf-8')
-    let ptr = this.eof
-    let len = buffer.length
-    assert(
-      (await this.log.write(buffer, 0, len, ptr)).bytesWritten === len
-    )
-    this.eof += len
-    return [ptr, len - 1] // ptr, len
-  }
-
-  async get() {
     let value = this.value
 
     //if (value instanceof Array) {
@@ -187,6 +168,9 @@ class File {
   }
 
   async flush() {
+    if (this.value === undefined)
+      return
+
     //if (this.value instanceof Array) {
       let [ptr, len, value] = this.value
       if (
@@ -259,8 +243,11 @@ class LazyArray extends Lazy {
 
   async get(key, default_value) {
     assert(typeof key === 'number')
-    if (key < 0 || key >= this.length)
-      return default_value
+    if (key < 0 || key >= this.length) {
+      if (default_value === undefined)
+        return undefined
+      set(key, default_value)
+    }
     let value = this.array[key]
 
     //if (value instanceof Array) {
@@ -377,8 +364,11 @@ class LazyObject extends Lazy {
 
   async get(key, default_value) {
     assert(typeof key === 'string')
-    if (!Object.prototype.hasOwnProperty.call(this.object, key))
-      return default_value
+    if (!Object.prototype.hasOwnProperty.call(this.object, key)) {
+      if (default_value === undefined)
+        return undefined
+      set(key, default_value)
+    }
     let value = this.object[key]
 
     //if (value instanceof Array) {