typicode / lowdb

Simple and fast JSON database
MIT License
21.3k stars 918 forks source link

Return default data when JSON file is empty #571

Closed stanleyume closed 10 months ago

stanleyume commented 1 year ago

Currently, if the JSON file is empty, it throws a JSON parse error.

undefined:1

SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at JSONFile.read ←[90m(file:///C:/nodeapps/browser/←[39mnode_modules/←[4mlowdb←[24m/lib/adapters/node/JSONFile.js:25:25←[90m)←[39m
    at async Low.read ←[90m(file:///C:/nodeapps/browser/←[39mnode_modules/←[4mlowdb←[24m/lib/core/Low.js:26:22←[90m)←[39m
    at async ←[90mfile:///C:/nodeapps/browser/←[39mindex.js:8:1

Node.js v18.14.0

With this change, it would return the default data if the adapter returns a falsy value, which covers both non-existing files and empty files.

Falsy: null, undefined, NaN, 0 , "" (empty string), false

orangecoding commented 1 year ago

Is there a reason not to merge this?

typicode commented 10 months ago

Thank you for the PR. This feels to me a bit too opinionated. I think by default JSONFile behavior should be to fail if syntax is incorrect (including if db.json is an empty string).

That being said, lowdb encourages the use of custom adapter to better fit a project needs. You could reuse your change this way:

class MyJSONFile<T> implements Adapter<T> {
  #adapter: TextFile

  constructor(filename: string) {
    this.#adapter = new TextFile(filename)
  }

  async read(): Promise<T | null> {
    const data = await this.#adapter.read()
    if (!data) {
      return null
    } else {
      return JSON.parse(data) as T
    }
  }

  write(obj: T): Promise<void> {
    return this.#adapter.write(JSON.stringify(obj, null, 2))
  }
}

// ...
const adapter = new MyJSONFile<Data>(filename)
const db = new Low<Data>(MyJSONFile, defaultData)