More development
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
All checks were successful
continuous-integration/appveyor/branch AppVeyor build succeeded
This commit is contained in:
parent
17830d7f8d
commit
0948885671
5 changed files with 174 additions and 19 deletions
33
core/db.mjs
33
core/db.mjs
|
@ -1,5 +1,6 @@
|
||||||
import { Low, JSONFile } from 'lowdb'
|
import { Low, JSONFile } from 'lowdb'
|
||||||
import { type } from 'os'
|
import { type } from 'os'
|
||||||
|
import { defaults, isObject } from './defaults.mjs'
|
||||||
|
|
||||||
export default function GetDB(util, log, filename = 'db.json') {
|
export default function GetDB(util, log, filename = 'db.json') {
|
||||||
let fullpath = util.getPathFromRoot('./' + filename)
|
let fullpath = util.getPathFromRoot('./' + filename)
|
||||||
|
@ -61,32 +62,30 @@ export default function GetDB(util, log, filename = 'db.json') {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db.addApplication = function(name) {
|
||||||
|
db.data.core[name] ||= {}
|
||||||
|
defaults(db.data.core[name], {
|
||||||
|
active: null,
|
||||||
|
latestInstalled: null,
|
||||||
|
latestVersion: null,
|
||||||
|
versions: [],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return db.read()
|
return db.read()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
db.data ||= {
|
if (!isObject(db.data)) {
|
||||||
core: {
|
log.warn(`File ${fullpath} was empty or not a json object, clearing it.`)
|
||||||
app: {
|
db.data = {}
|
||||||
active: null,
|
|
||||||
latestInstalled: null,
|
|
||||||
latestVersion: null,
|
|
||||||
versions: [],
|
|
||||||
},
|
|
||||||
manager: {
|
|
||||||
active: null,
|
|
||||||
latestInstalled: null,
|
|
||||||
latestVersion: null,
|
|
||||||
versions: [],
|
|
||||||
},
|
|
||||||
version: 1,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
defaults(db.data, { core: { version: 1 } })
|
||||||
|
|
||||||
return db.write()
|
return db.write()
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
function() { return db },
|
function() { return db },
|
||||||
function(err) {
|
function(err) {
|
||||||
let wrapped = new Error(`Error writing to ${fullpath}: ${err.code}`)
|
let wrapped = new Error(`Error writing to ${fullpath}: ${err.message} (${err.code})`)
|
||||||
wrapped.code = err.code
|
wrapped.code = err.code
|
||||||
throw wrapped
|
throw wrapped
|
||||||
}
|
}
|
||||||
|
|
25
core/defaults.mjs
Normal file
25
core/defaults.mjs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
// taken from isobject npm library
|
||||||
|
export function isObject(val) {
|
||||||
|
return val != null && typeof val === 'object' && Array.isArray(val) === false
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defaults(original, def) {
|
||||||
|
if (!isObject(original)) throw new Error('defaults called with non-object type')
|
||||||
|
|
||||||
|
Object.keys(original).forEach(key => {
|
||||||
|
if (isObject(original[key]) && def && isObject(def[key])) {
|
||||||
|
defaults(original[key], def[key])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (def) {
|
||||||
|
Object.keys(def).forEach(function(key) {
|
||||||
|
if (typeof original[key] === 'undefined') {
|
||||||
|
original[key] = def[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return original
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import Util from '../core/util.mjs'
|
||||||
var util = new Util(import.meta.url)
|
var util = new Util(import.meta.url)
|
||||||
var logger = {
|
var logger = {
|
||||||
info: stub(),
|
info: stub(),
|
||||||
|
warn: stub(),
|
||||||
error: stub(),
|
error: stub(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,10 +29,76 @@ t.test('Should auto create file with some defaults', async function() {
|
||||||
assert.ok(stat.size > 0)
|
assert.ok(stat.size > 0)
|
||||||
|
|
||||||
assert.ok(db.data.core)
|
assert.ok(db.data.core)
|
||||||
|
assert.ok(db.data.core.version)
|
||||||
|
assert.notOk(db.data.core.app)
|
||||||
|
assert.notOk(db.data.core.manager)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('Should apply defaults to existing file', async function() {
|
||||||
|
await assert.isRejected(fs.stat('./test/db_test.json'))
|
||||||
|
await fs.writeFile('./test/db_test.json', '{"test":true}')
|
||||||
|
|
||||||
|
let db = await lowdb(util, logger, 'db_test.json')
|
||||||
|
|
||||||
|
let stat = await fs.stat('./test/db_test.json')
|
||||||
|
assert.ok(stat.size > 0)
|
||||||
|
|
||||||
|
assert.ok(db.data.core)
|
||||||
|
assert.ok(db.data.core.version)
|
||||||
|
assert.strictEqual(db.data.test, true)
|
||||||
|
assert.notOk(db.data.core.app)
|
||||||
|
assert.notOk(db.data.core.manager)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('Should not fail if db is invalid', async function() {
|
||||||
|
logger.warn.reset()
|
||||||
|
await assert.isRejected(fs.stat('./test/db_test.json'))
|
||||||
|
await fs.writeFile('./test/db_test.json', '[]')
|
||||||
|
|
||||||
|
let db = await lowdb(util, logger, 'db_test.json')
|
||||||
|
|
||||||
|
let stat = await fs.stat('./test/db_test.json')
|
||||||
|
assert.ok(stat.size > 0)
|
||||||
|
|
||||||
|
assert.ok(db.data.core)
|
||||||
|
assert.ok(db.data.core.version)
|
||||||
|
assert.notOk(db.data.core.app)
|
||||||
|
assert.notOk(db.data.core.manager)
|
||||||
|
assert.ok(logger.warn.called)
|
||||||
|
assert.match(logger.warn.firstCall[0], /db_test.json/i)
|
||||||
|
assert.match(logger.warn.firstCall[0], /clear/i)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('Should support adding an application with defaults', async function() {
|
||||||
|
await assert.isRejected(fs.stat('./test/db_test.json'))
|
||||||
|
|
||||||
|
let db = await lowdb(util, logger, 'db_test.json')
|
||||||
|
|
||||||
|
let stat = await fs.stat('./test/db_test.json')
|
||||||
|
assert.ok(stat.size > 0)
|
||||||
|
|
||||||
|
assert.ok(db.data.core)
|
||||||
|
assert.ok(db.data.core.version)
|
||||||
|
assert.notOk(db.data.core.app)
|
||||||
|
assert.notOk(db.data.core.manager)
|
||||||
|
|
||||||
|
db.addApplication('app')
|
||||||
|
|
||||||
assert.ok(db.data.core.app)
|
assert.ok(db.data.core.app)
|
||||||
assert.ok(db.data.core.app.versions)
|
assert.ok(db.data.core.app.versions)
|
||||||
assert.ok(db.data.core.manager)
|
assert.strictEqual(db.data.core.app.active, null)
|
||||||
assert.ok(db.data.core.manager.versions)
|
assert.strictEqual(db.data.core.app.latestInstalled, null)
|
||||||
|
assert.strictEqual(db.data.core.app.latestVersion, null)
|
||||||
|
|
||||||
|
assert.notOk(db.data.core.herpderp)
|
||||||
|
|
||||||
|
db.addApplication('herpderp')
|
||||||
|
|
||||||
|
assert.ok(db.data.core.herpderp)
|
||||||
|
assert.ok(db.data.core.herpderp.versions)
|
||||||
|
assert.strictEqual(db.data.core.herpderp.active, null)
|
||||||
|
assert.strictEqual(db.data.core.herpderp.latestInstalled, null)
|
||||||
|
assert.strictEqual(db.data.core.herpderp.latestVersion, null)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.test('Should support reading from db', async function() {
|
t.test('Should support reading from db', async function() {
|
||||||
|
|
64
test/defaults.test.mjs
Normal file
64
test/defaults.test.mjs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import { Eltro as t, assert} from 'eltro'
|
||||||
|
import { isObject, defaults } from '../core/defaults.mjs'
|
||||||
|
|
||||||
|
t.describe('#isObject()', () => {
|
||||||
|
t.test('should return false for invalid objects', function() {
|
||||||
|
let tests = [
|
||||||
|
[],
|
||||||
|
'',
|
||||||
|
'asdf',
|
||||||
|
12341,
|
||||||
|
0,
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.strictEqual(isObject(check), false)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.test('should return true for valid objects', function() {
|
||||||
|
let tests = [
|
||||||
|
{},
|
||||||
|
new Object(),
|
||||||
|
]
|
||||||
|
|
||||||
|
tests.forEach(function(check) {
|
||||||
|
assert.strictEqual(isObject(check), true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.describe('#defaults()', () => {
|
||||||
|
t.test('should throw if original is missing or invalid', () => {
|
||||||
|
assert.throws(function() { defaults() })
|
||||||
|
assert.throws(function() { defaults('asdf') })
|
||||||
|
assert.throws(function() { defaults('') })
|
||||||
|
assert.throws(function() { defaults(null) })
|
||||||
|
assert.throws(function() { defaults(1234) })
|
||||||
|
assert.throws(function() { defaults([]) })
|
||||||
|
})
|
||||||
|
t.test('should not override existing variables', () => {
|
||||||
|
let assertOutput = { a: 2 }
|
||||||
|
defaults(assertOutput, { a: 1 })
|
||||||
|
|
||||||
|
assert.deepStrictEqual(assertOutput, { a: 2 })
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should allow nesting through objects', () => {
|
||||||
|
let def = { a: { b: 2 } }
|
||||||
|
let inside = { a: { c: 3} }
|
||||||
|
defaults(inside, def)
|
||||||
|
|
||||||
|
assert.deepStrictEqual(inside.a, {
|
||||||
|
b: 2,
|
||||||
|
c: 3,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should not return new reference', () => {
|
||||||
|
let assertInput = { a: 1 }
|
||||||
|
let existing = assertInput
|
||||||
|
defaults(assertInput, { b: 2 })
|
||||||
|
|
||||||
|
assert.strictEqual(assertInput, existing)
|
||||||
|
})
|
||||||
|
})
|
0
test/updater.test.mjs
Normal file
0
test/updater.test.mjs
Normal file
Loading…
Reference in a new issue