How to create a normal sails model without being in the models folder

前端 未结 5 1011
春和景丽
春和景丽 2021-02-13 05:50

So,

I\'m in the middle of implementing a plugin api for my application, and the plugins can have their own models, imagine this.

SimplePlugin = {
    pl         


        
5条回答
  •  长情又很酷
    2021-02-13 06:16

    What are you trying to do is not easy and a bit messy with Sails in the current state of the project. I'm referring to the v0.10 version. What you'll have to do is

    1. Inject the model definition found in SimplePlugin.SimpleModel into sails.models
    2. Inject a dummy controller for the model with _config: { rest: true }

    Please note that the code examples I posted are taken from a custom Sails hook I am working on and assume access to sails and the code examples to be executed during the loadHooks phase of Sails initialization / before the MiddlewareRegistry phase (compare: lib/app/load.js).

    1. Inject model definition

    Following the hints in the orm hook in Sails v0.10 you have to:

    • Get the models and adapters defined in api, merge your new model into the dictionary
    • Normalize the model definitions via sails.hooks.orm.normalizeModelDef
    • Load the normalized model definitions into Waterline
    • Unload exisisting adapter connections via teardown
    • Reinitialize Waterline
    • Expose the initialized Waterline collections to sails and the global scope via sails.hooks.orm.prepareModels (previously: sails.hooks.orm.exposeModels, changed with: 8d96895662)

    Because you have to reinitialize Waterline and reload all model definitions I'd recommend to collect all model definitions to inject and pass them to the inject function once. The example code below reflects this.

    ...
    
    function injectPluginModels(pluginModels, cb) {
      // copy sails/lib/hooks/orm/loadUserModules to make it accessible here
      var loadUserModelsAndAdapters = require('./loadUserModules')(sails);
    
      async.auto({
        // 1. load api/models, api/adapters
        _loadModules: loadUserModelsAndAdapters,
    
        // 2. Merge additional models,  3. normalize model definitions
        modelDefs: ['_loadModules', function(next){
          _.each(additionModels, function(aditionModel) {
             _.merge(sails.models, additionalModel);
          });
    
          _.each(sails.models, sails.hooks.orm.normalizeModelDef);
          next(null, sails.models);
        }],
    
        // 4. Load models into waterline, 5. tear down connections, 6. reinitialize waterline
        instantiatedCollections: ['modelDefs', function(next, stack){
          var modelDefs = stack.modelDefs;
    
          var waterline = new Waterline();
          _.each(modelDefs, function(modelDef, modelID){
            waterline.loadCollection(Waterline.Collection.extend(modelDef));
          });
    
          var connections = {};
    
          _.each(sails.adapters, function(adapter, adapterKey) {
            _.each(sails.config.connections, function(connection, connectionKey) {
              if (adapterKey !== connection.adapter) return;
              connections[connectionKey] = connection;
            });
          });
    
          var toTearDown = [];
    
          _.each(connections, function(connection, connectionKey) {
            toTearDown.push({ adapter: connection.adapter, connection: connectionKey });
          });
    
          async.each(toTearDown, function(tear, callback) {
             sails.adapters[tear.adapter].teardown(tear.connection, callback);
          }, function(){
             waterline.initialize({
               adapters: sails.adapters,
               connections: connections
             }, next)
          });
        }],
    
        // 7. Expose initialized models to global scope and sails
        _prepareModels: ['instantiatedCollections', sails.hooks.orm.prepareModels]
    
      }, cb);
    };
    
    ...
    

    Would allow you to:

    // Read your plugins
    ...
    
    var pluginModels = // Get all the plugin models
    injectPluginModels(pluginModels, function(){
      // Plugin models now available via global[pluginModel.globalId] and sails.models[pluginModel.identity]
    });
    

    2. Inject controller

    For each model that should be exposed via blueprint methods you have to:

    • Create a controller definition with matching identity and enabled blueprints
    • Save controller to sails.controllers[controllerId]
    • Save controller to sails.hooks.controllers.middleware[controllerId]

    The Sails MiddlewareRegistry will automatically pick up the controllers found in these objects.

    function mountBlueprintsForModels(pluginModels) {
      _.each(pluginModels, function(pluginModel){
        var controller = _.cloneDeep(pluginModel);
        controller._config = { rest: true };
    
        var controllerId = pluginModel.identity;
    
        if (!_.isObject(sails.controllers[controllerId])) {
          sails.controllers[controllerId] = controller;
        }
    
        if (!_.isObject(sails.hooks.controllers.middleware[controllerId])) {
          sails.hooks.controllers.middleware[controllerId] = controller;
        }
      });
    }
    

    3. In action

    // E.g. in /api/hooks/plugins/index.js
    /*
     * Module dependencies
     */
    
    var async = require('async'),
        _ = require('lodash'),
        waterline = require('waterline');
    
    module.exports = function(sails) {
    
      // injectPluginModels and mountBlueprintsForModels defined here
      ...
    
      return {
    
        initialize: function(cb) {
          sails.after('hook:orm:loaded', function() {
            yourNiftyPluginLoader(function(err, plugins) {
              // assuming plugin.models holds array of models for this plugin
              // customize for your use case
              var pluginModels = _.pluck(plugins, 'models');
              injectPluginModels(pluginModels, cb);
              mountBlueprintsForModels(pluginModels);
            });
          });
        }
    
      }
    
    }
    

提交回复
热议问题