Как создать обычную модель паруса не находясь в папке моделей

So,

Я нахожусь в процессе реализации плагина API для своего приложения, и плагины могут иметь свои собственные модели, представьте себе это.

SimplePlugin = {
    pluginName: 'simple',

    pluginConfig: {},

    SimpleModel: {

        attributes: {
            name: 'string'
        }

    } 

}

Поэтому мне нужно иметь возможность создавать «одноразовую» модель с функцией всякий раз, когда это необходимо, она должна иметь точно такую ​​​​же функциональность, как и другие модели, чтобы вы автоматически получали URL-адреса, такие как /simplePlugin/:id для find ..etc

Спасибо


person iConnor    schedule 13.01.2014    source источник
comment
@gorelative Как паруса узнали об этом? чтобы можно было настроить модель...   -  person iConnor    schedule 06.02.2014
comment
Вы используете v0.9.x или v0.10? Как вы реализуете плагин API, используя собственный хук?   -  person marionebl    schedule 07.02.2014
comment
Вы проверили github.com/balderdashy/waterline   -  person HaNdTriX    schedule 07.02.2014


Ответы (5)


То, что вы пытаетесь сделать, непросто и немного запутанно с Sails в текущем состоянии проекта. Я имею в виду версию v0.10. Что вам нужно сделать, это

  1. Вставьте определение модели, найденное в SimplePlugin.SimpleModel, в Sails.Models.
  2. Внедрите фиктивный контроллер для модели с помощью _config: { rest: true }

Обратите внимание, что примеры кода, которые я опубликовал, взяты из пользовательского хука Sails, над которым я работаю, и предполагают доступ к sails и примерам кода, которые будут выполняться во время фазы loadHooks инициализации Sails / перед фазой MiddlewareRegistry (сравните: lib/app/load.js).

1. Определение модели внедрения

Следуя подсказкам в orm хуке в Sails v0.10 вы должны:

  • Получите модели и адаптеры, определенные в api, добавьте новую модель в словарь.
  • Нормализуйте определения модели с помощью sails.hooks.orm.normalizeModelDef
  • Загрузите определения нормализованной модели в Waterline
  • Выгрузите существующие подключения адаптера через teardown
  • Повторно инициализировать ватерлинию
  • Предоставьте инициализированным коллекциям Waterline паруса и глобальную область видимости через sails.hooks.orm.prepareModels (ранее: sails.hooks.orm.exposeModels, изменено на: 8d96895662)

Поскольку вам нужно повторно инициализировать Waterline и перезагрузить все определения моделей, я бы рекомендовал собрать все определения моделей для внедрения и передать их функции внедрения один раз. Пример кода ниже отражает это.

...

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);
};

...

Позволит вам:

// 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. Инъекционный контроллер

Для каждой модели, которая должна быть представлена ​​с помощью методов чертежа, вы должны:

  • Создайте определение контроллера с соответствующим идентификатором и включенными схемами.
  • Сохранить контроллер в sails.controllers[controllerId]
  • Сохранить контроллер в sails.hooks.controllers.middleware[controllerId]

Паруса MiddlewareRegistry автоматически подберут контроллеры, найденные в этих объектах.

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. В действии

// 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);
        });
      });
    }

  }

}
person marionebl    schedule 10.02.2014
comment
Спасибо за ответ :) - person iConnor; 14.02.2014
comment
Фантастический ответ! Единственная часть, которая меня смущает, это функция yourNiftyPluginLoader. Откуда это? - person Chetan Shenoy; 28.10.2014
comment
yourNiftyPluginLoader меня тоже смутило, пока я не понял, что это была только функция, отвечающая за загрузку моделей плагинов/контроллеров/и т. д. из файловой системы. Вы можете использовать include-all, Sailes-Build-Dictionary или require-all, чтобы помочь вам в этом. - person Leeroy Brun; 16.03.2015
comment
Отличный ответ @marionebl. - person mikermcneil; 08.01.2016

РЕДАКТИРОВАТЬ: не работает полностью, так как коллекции назначаются соединениям при инициализации.

Кажется, есть лучшее решение, с 3 строками кода и без отключения/повторного подключения баз данных. Я только что изучил исходный код Waterline (см. https://github.com/balderdashy/waterline/blob/master/lib/waterline.js#L109). Можно сделать что-то вроде:

var Waterline = require('waterline');

// Other dependencies
var Schema = require('waterline-schema');
var CollectionLoader = require('waterline/lib/waterline/collection/loader');

var orm = new Waterline();

var config = {
    // Setup Adapters
    // Creates named adapters that have have been required
    adapters: {
        'default': 'mongo',
        mongo: require('sails-mongo')
    },

    // Build Connections Config
    // Setup connections using the named adapter configs
    connections: {
        'default': {
            adapter: 'mongo',
            url: 'mongodb://localhost:27017/sausage'
        }
    }
};

orm.initialize(config, function(err, data) {
    if (err) {
        throw err;
    }

    // ORM initialized, let's add another model dynamically
    var User = Waterline.Collection.extend({
       identity: 'user',
        connection: 'default',

        attributes: {
            first_name: 'string',
            last_name: 'string'
        }
    });
    orm.loadCollection(User);

    var defaults = config.defaults || {};

    // This is where the magic happens
    var loader = new CollectionLoader(User, orm.connections, defaults);
    var collection = loader.initialize(orm);
    orm.collections[collection.identity.toLowerCase()] = collection;

    // Done! You can now use orm.collections.user :-D
});
person emersion    schedule 02.08.2014

В v0.12 sails.hooks.orm.normalizeModelDef больше не существует. Также sails/lib/hooks/orm/loadUserModules перешел в модуль sails-hook-orm npm и больше не является частью парусов.

person Milzer    schedule 30.06.2016

Попробуйте следующее: «Загрузите модели, контроллеры, сервисы, политики и конфигурацию из указанных каталогов и внедрите их в основное приложение Sails».

https://github.com/leeroybrun/sails-util-mvcsloader

person eyn    schedule 13.09.2016

удивленные паруса не поддерживают это в 2018 году: я продолжил вышеуказанный пакет с помощью форка (ответ @eyn) с обновлениями, которые работают для парусов v1.x.x.

https://github.com/emahuni/sails-util-micro-apps

Я изменил его на это, потому что я много чего меняю в этом пакете. Вместо того, чтобы загружать только модели и контроллеры, я хочу, чтобы он загружал целые приложения, мини-приложения для микросервисной архитектуры в парусах. Это так, что вы можете создавать мини-приложения, которые можно объединить вместе, чтобы сформировать одно большое приложение из многократно используемого кода API.

person Emmanuel Mahuni    schedule 24.07.2018