关于构建包含使用 bookshelf.js 构建的模型的 Hapi.js 应用程序的建议

Suggestions on structuring Hapi.js app that includes Models built with bookshelf.js

我正在开发一个小型应用程序,我正在将 bookshelf.js 作为 ORM 进行集成。我正在努力的一件事情是构建我的应用程序,这样我就可以 require 其他模型,而不必在创建其他模型时注入它们。

例如:

中间件插件:

'use strict';

var Knex = require('knex');

exports.register = function(server, options, next) {
    var knex = Knex({
        client: 'mysql',
        connection: server.settings.app.mysql
    });
    var bookshelf = require('bookshelf')(knex);

    server.expose('bookshelf', bookshelf);

    next();
};

exports.register.attributes = {
    pkg: require('./package.json')
};

型号:

'use strict';

var Bluebird = require('bluebird');
var bcrypt = Bluebird.promisifyAll(require('bcrypt'));
var InvalidPasswordError = require('create-error')('InvalidPasswordError');


module.exports = function(bookshelf) {
    var User = bookshelf.Model.extend({
        tableName: 'user'
    }, {
        login: Bluebird.method(function(email, password) {
          return new this({email: email.toLowerCase().trim()})
            .fetch({require: true})
            .tap(function(user) {
                return bcrypt.compareAsync(password, user.get('encrypted_password'))
                    .then(function (matches) {
                        if (!matches) throw new InvalidPasswordError();
                    })
                })
            })
    });

    return User;
};

我在路由中的调用方式:

var bookshelf = server.plugins['bookshelf'].bookshelf;
var User = require('../models/user')(bookshelf);

server.route([
    {
        method: 'POST',
        path: '/auth/login',
        config: {
            auth: false,
            payload: { allow: 'application/json' },
            handler: function(request, reply) {
                var email = request.payload.email;
                var pwd = request.payload.password;

                User.login(email, pwd).then(function(user) {
                    reply(user.pick('api_token'));
                }).catch(User.NotFoundError, function() {
                    reply(Boom.badRequest('Invalid Email', 400));
                }).catch(function(err) {
                    reply(Boom.badRequest('Invalid Password', 400));
                });
            },
            validate: {
                payload: Joi.object().keys({
                    email: Joi.string().email().required(),
                    password: Joi.string().required()
                })
            }
        }
    }
]);

我感到困惑的部分是设置将存在于我的 User 模型中的关联。例如,用户通过联接 table 拥有多个项目。但是,如果我想设置该关联,我必须首先将我的 bookshelf 对象传递给每个模型(Project 和 UserProject),然后将关联模型 (UserProject) 传递给每个 User 和 Project。

这看起来不太干净。它可能会很快变得凌乱。还有其他人有 and/or 使用 ORM 构建 Hapi.js 或 Node 应用程序的经验吗?

看看 registry plugin .正如插件文档所述,您必须确保某处需要您的模型,以便调用 bookshelf.model

// db/index.js

var _ = require('lodash');
var Promise = require('bluebird');
var models = require('require-dir')('./models');
var bookshelf = require('bookshelf')(knexClient);

bookshelf.plugin('registry');

for (var model in models) {
  models[model] = models[model](_, Promise, bookshelf);
}

module.exports = models;

// db/models/User.js

module.exports = function (_, Promise, bookshelf) {

  var User = bookshelf.model('User', {

    tableName: 'users',

    projects: function () {
      return this.hasMany('Project');
    }

    // more proto props or relations
  },
  {

    // constructor props
  });

  return User;
};


// db/models/Project.js

module.exports = function (_, Promise, bookshelf) {

  var Project = bookshelf.model('Project', {

    tableName: 'projects'

  },
  {

  });

  return Project;
};

你可以在你的路线中要求模型,关系将全部挂钩。 projects 集合可以通过User 模型查询。下面我使用 fetchOne

// route.js
var User = require('../db').User;

module.exports = function (app) {

  app.get('/projects/:projectId', function (req, res) {

    return User
      .forge({ id: req.auth.userId })
      .projects()
      .query({where: { id: req.params.projectId } })
      .fetchOne()
      .then(function (project) {

        res.send(project);
      });

  });

};