lamassu-server/lib/settings-loader.js
2017-04-25 02:32:13 +03:00

151 lines
3.7 KiB
JavaScript

const path = require('path')
const fs = require('fs')
const _ = require('lodash/fp')
const argv = require('minimist')(process.argv.slice(2))
const pify = require('pify')
const db = require('./db')
const options = require('./options')
const logger = require('./logger')
const schemaPath = path.resolve(options.lamassuServerPath, 'lamassu-schema.json')
const schema = require(schemaPath)
let settingsCache
function loadFixture () {
const fixture = argv.fixture
const machine = argv.machine
if (fixture && !machine) throw new Error('Missing --machine parameter for --fixture')
const fixturePath = fixture => path.resolve(__dirname, '..', 'test', 'fixtures', fixture + '.json')
const promise = fixture
? pify(fs.readFile)(fixturePath(fixture)).then(JSON.parse)
: Promise.resolve([])
return promise
.then(values => _.map(v => {
return (v.fieldLocator.fieldScope.machine === 'machine')
? _.set('fieldLocator.fieldScope.machine', machine, v)
: v
}, values))
}
function isEquivalentField (a, b) {
return _.isEqual(
[a.fieldLocator.code, a.fieldLocator.fieldScope],
[b.fieldLocator.code, b.fieldLocator.fieldScope]
)
}
// b overrides a
function mergeValues (a, b) {
return _.unionWith(isEquivalentField, b, a)
}
function load (versionId) {
if (!versionId) throw new Error('versionId is required')
return Promise.all([loadConfig(versionId), loadAccounts()])
.then(([config, accounts]) => ({
config,
accounts
}))
}
function loadLatest () {
return Promise.all([loadLatestConfig(), loadAccounts()])
.then(([config, accounts]) => ({
config,
accounts
}))
}
function loadConfig (versionId) {
if (argv.fixture) return loadFixture()
const sql = `select data
from user_config
where id=$1 and type=$2`
return db.oneOrNone(sql, [versionId, 'config'])
.then(row => row ? row.data.config : [])
.then(validate)
}
function loadLatestConfig () {
if (argv.fixture) return loadFixture()
const sql = `select data
from user_config
where type=$1
order by id desc
limit 1`
return db.oneOrNone(sql, ['config'])
.then(row => row ? row.data.config : [])
.then(validate)
}
function checkConstraint (entry, constraint) {
switch (constraint.code) {
case 'min':
return entry.fieldValue.value >= constraint.min
default:
return true
}
}
function validateConstraint (entry, constraint) {
const isValid = checkConstraint(entry, constraint)
if (!isValid) logger.error(`Validation error: ${entry.fieldLocator.code} [${constraint.code}]`)
return isValid
}
function validateEntry (entry) {
const fieldCode = entry.fieldLocator.code
const schemaEntry = _.find(_.matchesProperty('code', fieldCode), schema.fields)
if (!schemaEntry) throw new Error(`Unsupported field: ${fieldCode}`)
const validations = schemaEntry.fieldValidation
return _.every(constraint => validateConstraint(entry, constraint), validations)
}
function validate (config) {
const isValid = _.every(validateEntry, config)
if (!isValid) throw new Error('Invalid config')
return config
}
function loadAccounts () {
const toFields = fieldArr => _.fromPairs(_.map(r => [r.code, r.value], fieldArr))
const toPairs = r => [r.code, toFields(r.fields)]
return db.oneOrNone('select data from user_config where type=$1', 'accounts')
.then(function (data) {
if (!data) return {}
return _.fromPairs(_.map(toPairs, data.data.accounts))
})
}
function settings () {
return settingsCache
}
function save (config) {
const sql = 'insert into user_config (type, data) values ($1, $2)'
return db.none(sql, ['config', config])
}
module.exports = {
settings,
loadConfig,
load,
loadLatest,
save,
loadFixture,
mergeValues
}