问题
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