-
-
Notifications
You must be signed in to change notification settings - Fork 40
Add support to declarative joins [SQLAlchemy] #585
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
base: main
Are you sure you want to change the base?
Conversation
✅ Deploy Preview for fastapi-filter ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #585 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 6 6
Lines 190 197 +7
=========================================
+ Hits 190 197 +7
|
arthurio
left a comment
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.
Thank you for your contribution Agus!
I very much prefer this declarative approach indeed. There is one caveat where people might shoot themselves in the foot, if they already have the join define on their base query (let say that they nest the related object in their response's object), it will throw sqlalchemy.exc.OperationalError "ambiguous column name" because the join is applied twice.
- Would it be possible to detect that the join is already present and skip it if so? If not, then people need to know that they have to decide which one they use, with the caveat that the filter join is applied only if there is a filter on that related field.
- One nit picky thing is that I don't love the
join_kwargsname, maybe justjoins(since you can have multiple)? - I also like that this is backward compatible but we should definitely add something in the docs (yeah I know they could use some love...).
- Finally, can we add a link to https://docs.sqlalchemy.org/en/20/core/selectable.html#sqlalchemy.sql.expression.Select.join so that people know what parameters are allowed in the
dict?
| search_field_name = "search" | ||
| join_kwargs = { | ||
| "address": { | ||
| "target": AddressFilter.Constants.model, |
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.
So here we can just omit the target?
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.
Yep! exactly :D, actually most of the time it would be enough to do something like this:
"address": {}
Thank you for doing such a useful package!
I was digging a bit into this topic, but I think I'd leave it as it is now: if the user joins twice then there will be an error in the query execution later. I tried to come up with an elegant "smart" solution, and I found that SQLAlchemy saves the tables will be joined in an attribute called just FYI: I was exploring this code for checking: @staticmethod
def is_table_joined(table_name: str, query: Select) -> bool:
"""Check if a table is already joined in a query by checking the setup join element.
It's of type: Tuple[_JoinTargetElement, Optional[_OnClauseElement], Optional["FromClause"], Dict[str, Any]]
"""
return any(table.name == table_name for (table, *_) in query._setup_joins)
Agreed!
Yes! Where should I add this docs? |
Just added a few lines of code to allow the "declarative" join definition. Another user created a similar PR but doing "magic" or "smart" joins, but I find the declarative approach clearer. For the test cases I just removed the manual joins in the select query and added the declarative approach