Commit f0c8b854 authored by Jarrod's avatar Jarrod 💬

Hook level models & model extension

parent 8d6e062b
const path = require('path')
const _ = require('lodash')
const includeAll = require('include-all');
module.exports = class SailsPluggable {
constructor (opt = {}) {
this.opt = opt
// FUTURE MAYBE: Can probably guess this based on the upstream hooks folder name?
this.opt.key = this.opt.key || this.opt.apiBase
this.core = this.opt.key === 'ahoy'
this.log = function () { sails.log[sails.hooks.ahoy.logLevel || 'info'](...arguments) }
if (this.core) {
this.subHooks = {}
}
return this.toHook()
}
async initialize (done) {
this.log(`Initializing Pluggable ${this.opt.key}`)
if (this.opt.helpers) {
sails.helpers[this.opt.key] = this.opt.helpers
}
await this.registerActions()
await this.registerModels()
done()
}
childLoaded (hook) {
if (Object.values(this.subHooks).filter(loaded => loaded).length === Object.values(this.subHooks).length) {
// Allow hook models to extend other models
_.each(sails.config.orm.moduleDefinitions.models, (def, extender) => {
if (def.extend) {
_.each(def.extend, (attributes, name) => {
sails.log.info(`Ahoy: Extending ${name}`, attributes)
const model = sails.config.orm.moduleDefinitions.models[name] // || sails.models[name]
if (!model || !model.attributes) {
sails.log.error(`Unable to extend model ${name} from ${extender}`)
}
_.each(attributes, (opt, field) => {
sails.config.orm.moduleDefinitions.models[name].attributes[field] = opt
})
})
}
})
// Reload the Sails ORM
sails.hooks.orm.reload((err) => {
if (err) { sails.log.error(`Unable to reload sails ORM`, err.stack) }
})
}
}
async registerActions () {
if (!this.opt.actions) {
return
}
_.each(this.opt.actions, (config, reqPath) => {
const key = `${this.opt.key || this.opt.apiBase}/${config.action}`
this.log(` - Registering action ${key}`)
sails.registerAction(require(path.join(this.opt.dir, `actions`, config.action)), key)
if (this.opt.apiBase) {
reqPath = reqPath.replace(/\//, `/${this.opt.apiBase}/`)
}
if (reqPath.charAt(reqPath.length - 1) === '/') {
reqPath = reqPath.substr(0, reqPath.length - 1)
}
config.action = key
config.package = this.opt.key
sails.config.routes[reqPath] = config
})
}
async registerModels () {
const models = includeAll({
dirname : path.join(this.opt.dir, 'models'),
filter : /(.*)\.js$/
});
if (_.isEmpty(models)) {
return
}
_.each(models, (def, name) => {
const lcName = name.toLowerCase()
// Check for model collisions. In theory userland models should take preference/override the core Ahoy user model
if (sails.models[lcName] || sails.config.orm.moduleDefinitions.models[lcName]) {
sails.log.warn(`Ahoy: Skip loading model "${name}" as it already exists on the Sails instance`)
return
}
def.name = lcName
def.globalId = name
sails.config.orm.moduleDefinitions.models[def.name] = def
})
}
toHook () {
const that = this
return function (sails) {
return {
const hook = {
ahoy: true,
initialize (done) {
if (that.opt.key !== 'ahoy') {
sails.log.info(`Delay initializing ${that.opt.key || that.opt.apiBase}`)
// Delay dependent hooks until ahoy has loaded
if (!that.core) {
sails.after('hook:ahoy:loaded', () => {
sails.log.info(`Initializing Pluggable ${that.opt.key || that.opt.apiBase}`)
sails.hooks[that.opt.key || that.opt.apiBase]
.registerActions(done)
that.initialize(done)
})
if (that.opt.helpers) {
sails.helpers[that.opt.key] = that.opt.helpers
}
return
}
sails.log.info(`Initializing Pluggable ${that.opt.key || that.opt.apiBase}`)
sails.hooks[that.opt.key || that.opt.apiBase]
.registerActions(done)
},
registerActions (cb) {
if (!that.opt.actions) {
return cb()
}
_.each(that.opt.actions, (config, reqPath) => {
const key = `${that.opt.key || that.opt.apiBase}/${config.action}`
sails.log.info(` - Registering action ${key}`)
sails.registerAction(require(path.join(that.opt.dir, `actions`, config.action)), key)
if (that.opt.apiBase) {
reqPath = reqPath.replace(/\//, `/${that.opt.apiBase}/`)
// Find other Ahoy hooks
_.each(sails.hooks, (hook, name) => {
if (hook.ahoy) {
that.subHooks[name] = false
sails.after(`hook:${name}:loaded`, () => {
that.subHooks[name] = true
that.childLoaded(name)
})
}
if (reqPath.charAt(reqPath.length - 1) === '/') {
reqPath = reqPath.substr(0, reqPath.length - 1)
}
config.action = key
config.package = that.opt.key
sails.config.routes[reqPath] = config
})
return cb()
// Wait for the ORM hook to load before we retrofit ourselves onto the app
sails.after('hook:orm:loaded', () => {
that.initialize(done)
})
},
...(that.opt.hook || that.opt.apiBase)
// Expose things passed in to the `hook` dictionary
...(that.opt.hook || {})
}
return hook
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment