New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Deep Filtering Feature #2452
Add Deep Filtering Feature #2452
Conversation
a716001
to
c5ccdee
Compare
@@ -29,22 +29,19 @@ module.exports = { | |||
.map(ast => ast.alias); | |||
|
|||
return <%= globalID %>.query(function(qb) { | |||
_.forEach(filters.where, (where, key) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Aurelsicoko @lauriejim We need to find a way to let the users modify the logic if they want, but the question is: "Do they really need to modify the Core Query System?"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean we can, for instance, put this utility functions inside of a folder that they can update but I don't see why should we duplicate the code in the different places (API Services / Content Manager and so on)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right! We could centralise everything in a single place but the users need to keep control if they want to edit something. It should not be hidden somewhere to avoid updates...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Aurelsicoko I think doing something like what @soupette did with the docs plugin and centralize everything but allow for model level overrides
symbol: value.symbol || '=' | ||
}; | ||
} | ||
qb.where(fieldKey, value.symbol, value.value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Should we ignore the field if it doesn't exist in the model's attributes (because the actual behaviour now is that you get a 500 Internal Error message)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kamalbennani @lauriejim realistically I think it should give a 4xx error. The error is with the user and their query. Ignoring it could make it look like there is nothing wrong. It should still toss an error, but in this case it isn't the server's fault 😜
); | ||
|
||
return controller(ctx, next); | ||
return controller(Object.assign({}, ctx, queryOpts, { send: ctx.send }), next, { populate: [] }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't populate any relation in the GraphQL context (Which will make things go faster :yay:)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've already did an update like that in this PR #2380, we should try to synchronise our work.
default: | ||
// Where. | ||
queryOpts.query = strapi.utils.models.convertParams(name, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to convertParams here because it's already done in the content manager
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right but I'm not 100% sure... it should work without converting the parameters but we're not doing randomly, I think there is a reason but I can't remember why.
c5ccdee
to
edbd3ca
Compare
} | ||
}).fetchAll({ | ||
withRelated: populate || _.keys(_.groupBy(_.reject(this.associations, { autoPopulate: false }), 'alias')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does anyone remember why here we reject the non-autoPopulated association but in the mongoose version we don't (https://github.com/strapi/strapi/pull/2452/files#diff-5a892334926e352d367245b7876dd6bdL10)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're rejecting the relations which don't have the autoPopulate
set to true (see https://github.com/strapi/strapi/blob/master/packages/strapi-generate-api/templates/mongoose/service.template#L24).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant that we are not doing it in packages/strapi-plugin-upload/config/queries/mongoose.js
} | ||
} | ||
}, | ||
"collectionName": "users-permissions_user" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be removed!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
queryOpts.query.id.symbol = 'IN'; | ||
// Construct the "where" query to only retrieve entries which are | ||
// related to this entry. | ||
_.set(queryOpts, ['query', association.via], obj[ref.primaryKey]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that there is no need to separate the manyToMany case from the rest of the logic, Could please confirm this @lauriejim @Aurelsicoko
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not only the manyToMany case but it's also the oneToMany
or manyToOne
process.
const fieldKey = (association && association.nature === 'manyToMany') | ||
? `${association.tableCollectionName}.${attributes[key].attribute}_${attributes[key].column}` | ||
: `${strapiModel.collectionName}.${key}`; | ||
if (_.isArray(value.value) && value.symbol !== 'IN') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is probably no need for this check! because we've removed the check in the GraphQL manyToMany relation
edbd3ca
to
07d621b
Compare
What's the best way to implement the unit tests, Yesterday I tried to run the existing test but it took at least 30/40 mins without success |
Jest test are broken on |
Cypress PR (#2348) merged! 🎉 |
@lauriejim how can I help to get this merged, I NEED it 🙏 |
Sorry guys quick question I'm new to strapi, does this PR only refer to being able to do a deep filter using GET params or does this also apply to GraphQL queries? I seem to be unable to deep filter with GraphQL |
@ssg-luke both of them, GET and GraphQL (right @kamalbennani ?) |
Yes :D |
b711340
to
03614fb
Compare
8a7834e
to
5434289
Compare
return <%= globalID %> | ||
.count() | ||
.where(filters.where); | ||
// Convert `params` object to filter compatible with Mongo. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove indentation
e2cc569
to
a971616
Compare
@kamalbennani @lauriejim any way i can help with this? It is becoming very hard to do simple queries without it. 🙏 |
@jacargentina We're doing our best to be able to merge this as soon as possible, we need to make sure that it breaks nothing and make it easy to integrate with existing Strapi projects effortlessly |
@kret13 it seems to be working just fine on a newly generated project :/ Could you provide us some steps to reproduce the same behaviour |
I haven't mentioned that it doesn't work when you add limit. Try with limit field to make count be number lesser than totalCount.
|
@kret13 I'll try to reproduce it again, thanks mate 💪 |
…ethod 'where' in the query class
…e the order of the pipelines matters
@kret13 it's fixed now, could you try again |
I tried this again and it seems that it's good now. |
I got a log when I filter with relation attribute
Look like an error but it's not. I have to check with actual master branch but when I install plugins, plugins permission disappear. |
The issue I report not happen on |
@lauriejim 3 months "birthday" soon. Any chance to get this merged on master ? |
@jacargentina it is being tested, last I saw last week there was issues that needed to be worked out that are being looked into. Maybe Jim can give a timeline but due to the size of this PR it cannot be merged without very detailed testing. |
fce66b5
into
strapi:feature/deep-filtering-mongoose-bookshelf
Hi guys, Thank you for your work @kamalbennani We are taking over the PR to help release it asap for the community ;) We are opening a new PR with the same commits merged into a freature branch on the main repo. Go there if you have new comments or questions 👍 |
My PR is a:
Main update on the:
Proposal
I think that generated service can be simplified a lot.
The problem with the actual implementation is that:
Which make it hard, very hard to maintain for both the developers and Strapi collaborators (Due to updates/Migrations)
We could use a simple technique where we implement a sort of a Query Service that handles fetching for us.
Here is an example of the code:
Mongoose Proposal
Post Service
@lauriejim @Aurelsicoko What do you think guys?
WIP (I'll add a complete description later on with concrete examples)
TODOs
Scenarios