131 lines
3.2 KiB
JavaScript
131 lines
3.2 KiB
JavaScript
import { setTimeout } from 'timers/promises'
|
|
import { Low, JSONFile, Memory } from 'lowdb'
|
|
import { defaults, isObject } from './defaults.mjs'
|
|
|
|
export default function GetDB(config, log, orgFilename = 'db.json') {
|
|
let adapter = new Memory()
|
|
let fullpath = 'in-memory'
|
|
if (orgFilename) {
|
|
fullpath = orgFilename
|
|
adapter = new JSONFile(fullpath)
|
|
}
|
|
const db = new Low(adapter)
|
|
|
|
db.id = 'id'
|
|
|
|
db.config = config
|
|
|
|
db.createId = function(collection) {
|
|
if (collection.length) {
|
|
return (collection[collection.length - 1].id || 0) + 1
|
|
}
|
|
return 1
|
|
}
|
|
|
|
db.get = function(collection, id, returnIndex = false) {
|
|
let col = db.getCollection(collection)
|
|
for (let i = col.length - 1; i >= 0; i--) {
|
|
if (col[i][db.id] === id) {
|
|
if (returnIndex) return i
|
|
return col[i]
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
db.getCollection = function(collection) {
|
|
if (typeof(collection) === 'string') {
|
|
return db.data[collection]
|
|
}
|
|
return collection
|
|
}
|
|
|
|
db.upsert = function(collection, item) {
|
|
let col = db.getCollection(collection)
|
|
if (item[db.id]) {
|
|
let i = db.get(col, item[db.id], true)
|
|
if (i !== null) {
|
|
col[i] = item
|
|
return
|
|
}
|
|
} else {
|
|
item[db.id] = db.createId(col)
|
|
}
|
|
col.push(item)
|
|
}
|
|
|
|
db.upsertFirst = function(collection, item) {
|
|
let col = db.getCollection(collection)
|
|
if (item[db.id]) {
|
|
let i = db.get(col, item[db.id], true)
|
|
if (i !== null) {
|
|
col[i] = item
|
|
return
|
|
}
|
|
} else {
|
|
item[db.id] = db.createId(col)
|
|
}
|
|
col.splice(0, 0, item)
|
|
}
|
|
|
|
db.remove = function(collection, itemOrId) {
|
|
let col = db.getCollection(collection)
|
|
let id = itemOrId
|
|
if (typeof(id) === 'object') {
|
|
id = id[db.id]
|
|
}
|
|
for (let i = col.length - 1; i >= 0; i--) {
|
|
if (col[i][db.id] === id) {
|
|
col.splice(i, 1)
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
db.addApplication = function(name) {
|
|
db.data.core[name] ||= {}
|
|
defaults(db.data.core[name], {
|
|
active: '',
|
|
latestInstalled: '',
|
|
latestVersion: '',
|
|
updater: '',
|
|
versions: [],
|
|
})
|
|
}
|
|
|
|
db.log = log
|
|
db._write = db.write.bind(db)
|
|
db.write = function() {
|
|
return this._write()
|
|
// Do couple of retries. Sometimes it fails randomly doing atomic writes.
|
|
.catch(() => { return setTimeout(20) })
|
|
.then(() => { return this._write() })
|
|
.catch(() => { return setTimeout(50) })
|
|
.then(() => { return this._write() })
|
|
.catch(() => { return setTimeout(100) })
|
|
.then(() => { return this._write() })
|
|
.catch((err) => {
|
|
this.log.error(err, 'Error saving to db')
|
|
})
|
|
}
|
|
|
|
return db.read()
|
|
.then(function() {
|
|
if (!isObject(db.data)) {
|
|
db.log.warn(`File ${fullpath} was empty or not a json object, clearing it.`)
|
|
db.data = {}
|
|
}
|
|
defaults(db.data, { core: { version: 1 } })
|
|
|
|
return db.write()
|
|
})
|
|
.then(
|
|
function() { return db },
|
|
function(err) {
|
|
let wrapped = new Error(`Error writing to ${fullpath}: ${err.message} (${err.code})`)
|
|
wrapped.code = err.code
|
|
throw wrapped
|
|
}
|
|
)
|
|
}
|