@resin/pinejs
Version:
Pine.js is a sophisticated rules-driven API engine that enables you to define rules in a structured subset of English. Those rules are used in order for Pine.js to generate a database schema and the associated [OData](http://www.odata.org/) API. This make
268 lines (255 loc) • 7.48 kB
text/coffeescript
Promise = require 'bluebird'
permissions = require '../sbvr-api/permissions'
uiModel = '''
Vocabulary: ui
Term: text
Concept type: Text (Type)
Term: name
Concept type: Short Text (Type)
Term: textarea
--Database id Field: name
Reference Scheme: text
Fact type: textarea is disabled
Fact type: textarea has name
Necessity: Each textarea has exactly 1 name
Necessity: Each name is of exactly 1 textarea
Fact type: textarea has text
Necessity: Each textarea has exactly 1 text'''
# Middleware
isServerOnAir = do ->
resolve = null
promise = new Promise (_resolve) ->
resolve = _resolve
(value) ->
if value?
if promise.isPending()
resolve(value)
resolve = null
else
promise = Promise.fulfilled(value)
return promise
serverIsOnAir = (req, res, next) ->
isServerOnAir().then (onAir) ->
if onAir
next()
else
next('route')
# Setup function
exports.config =
models: [
modelName: 'ui',
modelText: uiModel
apiRoot: 'ui'
customServerCode: exports
]
exports.setup = (app, sbvrUtils, db) ->
uiApi = sbvrUtils.api.ui
devApi = sbvrUtils.api.dev
setupModels = (tx) ->
uiApiTx = uiApi.clone
passthrough:
tx: tx
req: permissions.root
uiApiTx.get
resource: 'textarea'
options:
$select: 'id'
$filter:
name: 'model_area'
.then (result) ->
if result.length is 0
# Add a model_area entry if it doesn't already exist.
uiApiTx.post
resource: 'textarea'
body:
name: 'model_area'
text: ' '
.then ->
devApi.get
resource: 'model'
passthrough:
tx: tx
req: permissions.rootRead
options:
$select: ['is_of__vocabulary', 'model_value']
$filter:
model_type: 'se'
is_of__vocabulary: 'data'
.then (result) ->
if result.length is 0
throw new Error('No SE data model found')
instance = result[0]
sbvrUtils.executeModel(tx,
apiRoot: instance.is_of__vocabulary
modelText: instance.model_value
)
.then ->
isServerOnAir(true)
.catch (err) ->
isServerOnAir(false)
app.get '/onAir', (req, res, next) ->
isServerOnAir()
.then (onAir) ->
res.json(onAir)
app.post '/update', permissions.checkPermissionsMiddleware('all'), serverIsOnAir, (req, res, next) ->
res.sendStatus(404)
app.post '/execute', permissions.checkPermissionsMiddleware('all'), (req, res, next) ->
uiApi.get
resource: 'textarea'
passthrough: req: permissions.rootRead
options:
$select: 'text'
$filter:
name: 'model_area'
.then (result) ->
if result.length is 0
throw new Error('Could not find the model to execute')
modelText = result[0].text
db.transaction (tx) ->
sbvrUtils.executeModel(tx,
apiRoot: 'data'
modelText: modelText
)
.then ->
uiApi.patch
resource: 'textarea'
passthrough:
tx: tx
req: permissions.root
options:
$filter:
name: 'model_area'
body:
is_disabled: true
.then ->
isServerOnAir(true)
res.sendStatus(200)
.catch (err) ->
isServerOnAir(false)
res.status(404).json(err)
app.post '/validate', permissions.checkPermissionsMiddleware('get'), (req, res, next) ->
sbvrUtils.runRule('data', req.body.rule)
.then (results) ->
res.json(results)
.catch (err) ->
console.log('Error validating', err)
res.sendStatus(404)
app.delete '/cleardb', permissions.checkPermissionsMiddleware('delete'), (req, res, next) ->
db.transaction (tx) ->
tx.tableList()
.then (result) ->
Promise.all result.rows.map (table) ->
tx.dropTable(table.name)
.then ->
sbvrUtils.executeStandardModels(tx)
.then ->
# TODO: HACK: This is usually done by config-loader and should be done there
# In general cleardb is very destructive and should really go through a full "reboot" procedure to set everything up again.
console.warn('DEL /cleardb is very destructive and should really be followed by a full restart/reload.')
sbvrUtils.executeModels(tx, exports.config.models)
.then ->
setupModels(tx)
.then ->
res.sendStatus(200)
.catch (err) ->
console.error('Error clearing db', err, err.stack)
res.sendStatus(503)
app.put '/importdb', permissions.checkPermissionsMiddleware('set'), (req, res, next) ->
queries = req.body.split(';')
db.transaction (tx) ->
Promise.reduce(
queries
(result, query) ->
query = query.trim()
if query.length > 0
tx.executeSql(query).catch((err) ->
throw [query, err]
)
null
)
.then ->
res.sendStatus(200)
.catch (err) ->
console.error('Error importing db', err, err.stack)
res.sendStatus(404)
app.get '/exportdb', permissions.checkPermissionsMiddleware('get'), (req, res, next) ->
db.transaction (tx) ->
tx.tableList("name NOT LIKE '%_buk'")
.then (result) ->
exported = ''
Promise.all result.rows.map (table) ->
tableName = table.name
exported += 'DROP TABLE IF EXISTS "' + tableName + '";\n'
exported += table.sql + ';\n'
tx.executeSql('SELECT * FROM "' + tableName + '";')
.then (result) ->
insQuery = ''
result.rows.forEach (currRow) ->
notFirst = false
insQuery += 'INSERT INTO "' + tableName + '" ('
valQuery = ''
for own propName of currRow
if notFirst
insQuery += ','
valQuery += ','
else
notFirst = true
insQuery += '"' + propName + '"'
valQuery += "'" + currRow[propName] + "'"
insQuery += ') values (' + valQuery + ');\n'
exported += insQuery
.return(exported)
.then (exported) ->
res.json(exported)
.catch (err) ->
console.error('Error exporting db', err, err.stack)
res.sendStatus(503)
app.post '/backupdb', permissions.checkPermissionsMiddleware('all'), serverIsOnAir, (req, res, next) ->
db.transaction (tx) ->
tx.tableList("name NOT LIKE '%_buk'")
.then (result) ->
Promise.all result.rows.map (currRow) ->
tableName = currRow.name
tx.dropTable(tableName + '_buk', true)
.then ->
tx.executeSql('ALTER TABLE "' + tableName + '" RENAME TO "' + tableName + '_buk";')
.then ->
res.sendStatus(200)
.catch (err) ->
console.error('Error backing up db', err, err.stack)
res.sendStatus(404)
app.post '/restoredb', permissions.checkPermissionsMiddleware('all'), serverIsOnAir, (req, res, next) ->
db.transaction (tx) ->
tx.tableList("name LIKE '%_buk'")
.then (result) ->
Promise.all result.rows.map (currRow) ->
tableName = currRow.name
tx.dropTable(tableName[0...-4], true)
.then ->
tx.executeSql('ALTER TABLE "' + tableName + '" RENAME TO "' + tableName[0...-4] + '";')
.then ->
res.sendStatus(200)
.catch (err) ->
console.error('Error restoring db', err, err.stack)
res.sendStatus(404)
app.all('/data/*', serverIsOnAir, sbvrUtils.handleODataRequest)
app.get('/Auth/*', serverIsOnAir, sbvrUtils.handleODataRequest)
app.merge('/ui/*', sbvrUtils.handleODataRequest)
app.patch('/ui/*', sbvrUtils.handleODataRequest)
app.delete '/', serverIsOnAir, (req, res, next) ->
Promise.all([
uiApi.patch
resource: 'textarea'
passthrough: req: permissions.root
options:
$filter:
name: 'model_area'
body:
text: ''
name: 'model_area'
is_disabled: false
sbvrUtils.deleteModel('data')
]).then ->
isServerOnAir(false)
res.sendStatus(200)
db.transaction(setupModels)