Is there a way to override sails.js waterline endpoint with custom controller, but keep built in pagination, and filtering?

泪湿孤枕 提交于 2020-07-10 06:53:11

问题


I have defined a model, and I like that I get pagination, and filtering out of the box with waterline and blueprint. However, I need to add a where clause to all requests. I don't wasn't the client to add the where. I still want to get all the magical sails.js pagination and filters though that I lose when I create an override controller.

Does anyone know how to get my cake and eat it too?


回答1:


I initially went the route that arbuthnott suggested, however I was frustrated that it only worked for blueprint and not waterline ORM. I wanted consistent behavior across my API. Because of the way that sails uses mixins its a bit tricky to monkeypatch because at instantiation time the ORM methods are not added to the models.

The way this works, is that with a hook, once the ORM is loaded, it will monkeypatch each of the methods with a find that merges in your defaultScope criteria. The benefit of doing it this way over policies is that it applies to waterline ORM and blueprint so that you get consistent behavior

In each model you want to add a criteria to, add the following scope:

defaultScope: {
  where: {
    status: {
      '>': 0,
      '>=': sails.config.catalogVersions.status,
    },
  },
},

in api/hooks add a new file with the following:

const _ = require('lodash');
const _monkeyPatch = (model, method) => {
  const _method = model[method];
  model[method] = (...args) => {
    let criteria = args[0] || {};
    criteria = _.merge(model.defaultScope || {}, criteria);
    args[0] = criteria;
    return _method.apply(model, args);
  };
};
const applyScopeToFinds = (model) => {
  _monkeyPatch(model, 'find');
  _monkeyPatch(model, 'findOne');
  _monkeyPatch(model, 'findOrCreate');
  _monkeyPatch(model, 'count');
};

module.exports = (sails) => {
  return {
    initialize: async (next) => {
      sails.on('hook:orm:loaded', () => {
        _.forEach(sails.models, (model) => applyScopeToFinds(model));
      });
      return next();
    },
  };
};



回答2:


I think you could do this using policies. In your config/policies.js you'd have to add a custom policy to the find blueprint action for each model you wanted to do this:

ArticleController: {
    find: ['myCustomPolicy'],
    ...
}

Then the policy could add in query filters just as if they had come from the client. So for example, if your Article model had a boolean deleted flag set up, then api/policies/myCustomPolicy.js might look like:

module.exports = function(req, res, next) {
    req.query.deleted = false;
    return next();
};

You could also add this to findOne blueprint action if needed. You have to add a line to policies.js for each Model you want this to happen on, but this gives you exact control which models it applies to, and you only have to write the policy itself once.



来源:https://stackoverflow.com/questions/62395812/is-there-a-way-to-override-sails-js-waterline-endpoint-with-custom-controller-b

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!