@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
217 lines • 8.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.setup = void 0;
const Bluebird = require("bluebird");
const fs = require("fs");
const _ = require("lodash");
const path = require("path");
const sbvrUtils = require("../sbvr-api/sbvr-utils");
const permissions = require("../sbvr-api/permissions");
const getOrCreate = async (authApiTx, resource, uniqueFields, extraFields) => {
const [result] = (await authApiTx.get({
resource,
options: {
$select: 'id',
$filter: uniqueFields,
},
}));
if (result != null) {
return result.id;
}
const { id } = (await authApiTx.post({
resource,
body: { ...uniqueFields, ...extraFields },
options: { returnResource: false },
}));
return id;
};
const getOrCreatePermission = async (authApiTx, permissionName) => {
try {
return getOrCreate(authApiTx, 'permission', { name: permissionName });
}
catch (e) {
e.message = `Could not create or find permission "${permissionName}": ${e.message}`;
throw e;
}
};
exports.setup = (app) => {
const loadConfig = (data) => sbvrUtils.db.transaction(async (tx) => {
const authApiTx = sbvrUtils.api.Auth.clone({
passthrough: {
tx,
req: permissions.root,
},
});
const { users } = data;
if (users != null) {
const permissionsCache = {};
users.forEach((user) => {
if (user.permissions == null) {
return;
}
user.permissions.forEach((permissionName) => {
if (permissionsCache[permissionName] != null) {
return;
}
permissionsCache[permissionName] = getOrCreatePermission(authApiTx, permissionName);
});
});
await Bluebird.map(users, async (user) => {
try {
const userID = await getOrCreate(authApiTx, 'user', {
username: user.username,
}, {
password: user.password,
});
if (user.permissions != null) {
await Bluebird.map(user.permissions, async (permissionName) => {
const permissionID = await permissionsCache[permissionName];
await getOrCreate(authApiTx, 'user__has__permission', {
user: userID,
permission: permissionID,
});
});
}
}
catch (e) {
e.message = `Could not create or find user "${user.username}": ${e.message}`;
throw e;
}
});
}
await Bluebird.map(data.models, async (model) => {
if ((model.abstractSql != null || model.modelText != null) &&
model.apiRoot != null) {
try {
await sbvrUtils.executeModel(tx, model);
const apiRoute = `/${model.apiRoot}/*`;
app.options(apiRoute, (_req, res) => res.sendStatus(200));
app.all(apiRoute, sbvrUtils.handleODataRequest);
console.info('Successfully executed ' + model.modelName + ' model.');
}
catch (err) {
const message = `Failed to execute ${model.modelName} model from ${model.modelFile}`;
if (_.isError(err)) {
err.message = message;
throw err;
}
throw new Error(message);
}
}
if (model.customServerCode != null) {
let customCode;
if (typeof model.customServerCode === 'string') {
try {
customCode = nodeRequire(model.customServerCode).setup;
}
catch (e) {
e.message = `Error loading custom server code: '${e.message}'`;
throw e;
}
}
else if (_.isObject(model.customServerCode)) {
customCode = model.customServerCode.setup;
}
else {
throw new Error(`Invalid type for customServerCode '${typeof model.customServerCode}'`);
}
if (typeof customCode !== 'function') {
return;
}
return customCode(app, sbvrUtils, sbvrUtils.db);
}
});
});
const loadConfigFile = (configPath) => {
console.info('Loading config:', configPath);
return Bluebird.resolve(Promise.resolve().then(() => require(configPath)));
};
const loadApplicationConfig = Bluebird.method(async (config) => {
try {
if (require.extensions['.coffee'] == null) {
try {
require('coffeescript/register');
}
catch (e) {
}
}
if (require.extensions['.ts'] == null) {
try {
require('ts-node/register/transpile-only');
}
catch (e) {
}
}
console.info('Loading application config');
let root;
let configObj;
if (config == null) {
root = path.resolve(process.argv[2]) || __dirname;
configObj = await loadConfigFile(path.join(root, 'config.json'));
}
else if (typeof config === 'string') {
root = path.dirname(config);
configObj = await loadConfigFile(config);
}
else if (_.isObject(config)) {
root = process.cwd();
configObj = config;
}
else {
throw new Error(`Invalid type for config '${typeof config}'`);
}
const resolvePath = (s) => {
if (path.isAbsolute(s)) {
return s;
}
return path.join(root, s);
};
await Bluebird.map(configObj.models, async (model) => {
if (model.modelFile != null) {
model.modelText = await fs.promises.readFile(resolvePath(model.modelFile), 'utf8');
}
if (typeof model.customServerCode === 'string') {
model.customServerCode = resolvePath(model.customServerCode);
}
if (model.migrations == null) {
model.migrations = {};
}
const migrations = model.migrations;
if (model.migrationsPath) {
const migrationsPath = resolvePath(model.migrationsPath);
delete model.migrationsPath;
await Bluebird.map(fs.promises.readdir(migrationsPath), async (filename) => {
const filePath = path.join(migrationsPath, filename);
const [migrationKey] = filename.split('-', 1);
switch (path.extname(filename)) {
case '.coffee':
case '.ts':
case '.js':
migrations[migrationKey] = nodeRequire(filePath);
break;
case '.sql':
migrations[migrationKey] = await fs.promises.readFile(filePath, 'utf8');
break;
default:
console.error(`Unrecognised migration file extension, skipping: ${path.extname(filename)}`);
}
});
}
if (model.initSqlPath) {
const initSqlPath = resolvePath(model.initSqlPath);
model.initSql = await fs.promises.readFile(initSqlPath, 'utf8');
}
});
await loadConfig(configObj);
}
catch (err) {
console.error('Error loading application config', err, err.stack);
process.exit(1);
}
});
return {
loadConfig,
loadApplicationConfig,
};
};
//# sourceMappingURL=config-loader.js.map