That's the (almost) final version if you're interrested: 
https://gist.github.com/silenius/568aca7545e1bc0400b53b6ec157807d

On Wednesday, June 19, 2019 at 4:44:55 PM UTC+2, Julien Cigar wrote:
>
>
>
> On Wednesday, June 19, 2019 at 4:09:55 PM UTC+2, Mike Bayer wrote:
>>
>>
>>
>> On Wed, Jun 19, 2019, at 4:48 AM, Julien Cigar wrote:
>>
>> Thank you very much, it almost works !
>>
>> I have one minor issue, as translation_cls is involved in joined load 
>> inheritance the select([translation_cls], ...) results in:
>>
>>                  SELECT
>>                     content_translation.language_id AS language_id,
>>                     content_translation.content_id AS content_id,
>>                     content_translation.title AS title,
>>                     content_translation.description AS description,
>>                     content_translation.fts AS fts,
>>                     document_translation.language_id AS language_id,
>>                     document_translation.content_id AS content_id,
>>                     document_translation.body AS body,
>>                 (...)
>>
>> which lead to a 2019-06-18 17:47:04.498 CEST [51817] ERROR:  column 
>> reference "content_id" is ambiguous at character 3155
>> for the foreign(_alias2.content_id) == content_cls.content_id,
>>
>> I could list and alias individual columns, but I wondered if SQLAlchemy 
>> could do this automatically ?
>>
>>
>> for the joined inheirtance, you need to compose the SELECT against both 
>> tables individually with the JOIN you want between them, I would probably 
>> use something like
>>
>> select([MyClass]).select_from(MyClass.__mapper__.selectable)
>>
>
> That's what I tried initially but it doesn't work in this case ("outer" 
> query had ambigous column reference too)
>  
>
>>
>>
>>
>>
>>
>> Cheers,
>> Julien
>>
>>
>> On Wednesday, June 19, 2019 at 7:32:24 AM UTC+2, Mike Bayer wrote:
>>
>>
>> This test doesn't run yet because it looks like you need to have 
>> initializers for things like Content.current_translation, the setup_class 
>> fails right now because that isn't handled.
>>
>> In any case, adapting the window recipe from 
>> https://docs.sqlalchemy.org/en/13/orm/join_conditions.html#row-limited-relationships-with-window-functions
>>  
>> to the code here can be done directly:
>>
>>     _alias = (
>>         select(
>>             [
>>                 translation_cls,
>>                 func.row_number()
>>                 .over(
>>                     order_by=[
>>                         desc(
>>                             translation_cls.language_id
>>                             == bindparam(
>>                                 None,
>>                                 callable_=lambda: current_locale(),
>>                                 type_=String(),
>>                             )
>>                         ),
>>                         desc(
>>                             translation_cls.language_id
>>                             == bindparam(
>>                                 None,
>>                                 callable_=lambda: fallback_locale(),
>>                                 type_=String(),
>>                             )
>>                         ),
>>                     ],
>>                     partition_by=translation_cls.content_id,
>>                 )
>>                 .label("index"),
>>             ]
>>         )
>>         .where(
>>             and_(
>>                 translation_cls.language_id.in_(
>>                     (
>>                         bindparam(
>>                             None,
>>                             callable_=lambda: current_locale(),
>>                             type_=String(),
>>                         ),
>>                         bindparam(
>>                             None,
>>                             callable_=lambda: fallback_locale(),
>>                             type_=String(),
>>                         ),
>>                     )
>>                 )
>>             )
>>         )
>>         .alias()
>>     )
>>
>>     _alias2 = aliased(translation_cls, _alias)
>>
>>     content_mapper.add_properties(
>>         {
>>             "current_translation": relationship(
>>                 _alias2,
>>                 primaryjoin=and_(
>>                     foreign(_alias2.content_id) == content_cls.content_id,
>>                     _alias.c.index == 1,
>>                 ),
>>                 lazy="joined",
>>                 uselist=False,
>>                 innerjoin=True,
>>                 viewonly=True,
>>                 bake_queries=False,
>>             ),
>>         }
>>     )
>>
>>
>> On Tue, Jun 18, 2019, at 11:34 AM, Julien Cigar wrote:
>>
>> Hello Mike,
>>
>> As always thank you for your quick and useful reply. I might not need 
>> LATERAL but would be very interrested to see a solution with WINDOW 
>> functions ..
>>
>> I've added a small test case with some comment on what I'd like to 
>> achieve. Basically what I would like is to be able to select the "current" 
>> translation in one query, and that it is transparent (it's a Pyramid 
>> plugin), that's why I'm also using hybrid properties
>>
>>
>> On Tuesday, June 18, 2019 at 3:38:36 PM UTC+2, Mike Bayer wrote:
>>
>>
>>
>> On Tue, Jun 18, 2019, at 6:21 AM, Julien Cigar wrote:
>>
>> Hello,
>>
>> I'm trying to add a 'read-only' relationship involving a subquery and I 
>> have some problems with remote and foreign sides, SQLAlchemy returns:
>>
>> sqlalchemy.exc.ArgumentError: Relationship Folder.current_translation 
>> could not determine any unambiguous local/remote column pairs based on join 
>> condition and remote_side arguments.  Consider using the remote() 
>> annotation to accurately mark those elements of the join condition that are 
>> on the remote side of the relationship.
>>
>> I've copied my code here 
>> https://gist.github.com/silenius/e2c7fb393864b3f1fee8131336dd8b61
>>
>>
>>
>> Any idea what could be wrong ..? 
>>
>> Basically I have a "translation" table and I'd like to JOIN that table 
>> for the current translation or the "fallback" language, so something like:
>> select c.id, t.* from content c JOIN LATERAL (select ct.* from 
>> content_translation ct WHERE ct.content_id=c.id order by 
>> ct.language_id='fr' desc, ct.language_id='en' desc limit 1) as t ON 
>> t.content_id = c.id WHERE c.id=4855;
>>
>>
>>
>> hiya -
>>
>> unfortunately JOIN LATERAL is not supported, at least in all cases, as 
>> the target of a relationship(), because loading such as lazy loading does 
>> not use JOIN at all, and it's not clear if the LATERAL construct would work 
>> with other forms of relationship loading as well.    That is, it *might* 
>> work for some cases, though it's never been tested, and likely wont work 
>> for most/all cases.  Also in your example I don't see any usage of the 
>> lateral() modifier on your subquery.
>>
>> It would be best to compose the ON clause of the join using more 
>> traditional methods, e.g. that the "right" side of the join is a subquery 
>> that does not use any correlation, and the ON clause relates the left and 
>> right sides together.
>>
>> Within the example given, the "primaryjoin" argument refers to the ON 
>> clause of a JOIN, so generally a subquery would not be located here.  
>> Additionally, "as_scalar()", which is being renamed to "scalar_subquery()", 
>> indicates that this query is a so-called "scalar" subquery that returns 
>> exactly one row in one column and therefore acts as a column expression to 
>> be used in the WHERE clause, but this would not work as an ON clause in a 
>> JOIN by itself unless it were equated to something (but again, you'd need 
>> LATERAL for correlation to work in the ON clause).
>>
>> Looking at the actual SQL you're looking for, everything about it seems 
>> to be fully "traditional" in how the join is composed except for the detail 
>> that you're trying to get the first row only that matches in 
>> content_translation.    We have a recipe for row-limited relationships 
>> using window functions which will likely fit here directly, at 
>> https://docs.sqlalchemy.org/en/13/orm/join_conditions.html#row-limited-relationships-with-window-functions
>>  
>> .   you'd want to add "uselist=False" to your relationship() if you are 
>> looking for a many-to-one style relationship.  The window function works by 
>> including a "row number", eg. index of a row, partitioned against the 
>> groupings within which you'd want to be limiting, in this case it can 
>> perhaps be partition_by=[ct.content_id], and it then orders within those 
>> partitions where you could apply your interesting "lang='fr' desc, 
>> lang='en' desc" trick above.    Then the limit is applied in the ON clause 
>> by asking for "partition.c.index == 1".
>>
>> if you can share rudimentary mappings I can show you the composition, 
>> although the example as given in the docs should translate fairly directly 
>> here.
>>
>>
>>
>>
>>
>>
>>
>> Thank you!
>>
>> Julien
>>
>>
>> --
>> SQLAlchemy - 
>> The Python SQL Toolkit and Object Relational Mapper
>>  
>> http://www.sqlalchemy.org/
>>  
>> To post example code, please provide an MCVE: Minimal, Complete, and 
>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
>> description.
>> --- 
>> You received this message because you are subscribed to the Google Groups 
>> "sqlalchemy" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to sqlal...@googlegroups.com.
>> To post to this group, send email to sqlal...@googlegroups.com.
>> Visit this group at https://groups.google.com/group/sqlalchemy.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/sqlalchemy/16dddc84-d927-44e0-95dc-da9f579da733%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/sqlalchemy/16dddc84-d927-44e0-95dc-da9f579da733%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>>
>> --
>> SQLAlchemy - 
>> The Python SQL Toolkit and Object Relational Mapper
>>  
>> http://www.sqlalchemy.org/
>>  
>> To post example code, please provide an MCVE: Minimal, Complete, and 
>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
>> description.
>> --- 
>> You received this message because you are subscribed to the Google Groups 
>> "sqlalchemy" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to sqlal...@googlegroups.com.
>> To post to this group, send email to sqlal...@googlegroups.com.
>> Visit this group at https://groups.google.com/group/sqlalchemy.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/sqlalchemy/8bfe074c-0ab4-4e71-8b43-afd90a6743aa%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/sqlalchemy/8bfe074c-0ab4-4e71-8b43-afd90a6743aa%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>> *Attachments:*
>>
>>    - trans.py
>>    
>>
>>
>> --
>> SQLAlchemy - 
>> The Python SQL Toolkit and Object Relational Mapper
>>  
>> http://www.sqlalchemy.org/
>>  
>> To post example code, please provide an MCVE: Minimal, Complete, and 
>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full 
>> description.
>> --- 
>> You received this message because you are subscribed to the Google Groups 
>> "sqlalchemy" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to sqlal...@googlegroups.com.
>> To post to this group, send email to sqlal...@googlegroups.com.
>> Visit this group at https://groups.google.com/group/sqlalchemy.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/sqlalchemy/337cb354-4bd5-43f5-aee8-9ecce97a31f1%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/sqlalchemy/337cb354-4bd5-43f5-aee8-9ecce97a31f1%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>> For more options, visit https://groups.google.com/d/optout.
>>
>>
>>

-- 
SQLAlchemy - 
The Python SQL Toolkit and Object Relational Mapper

http://www.sqlalchemy.org/

To post example code, please provide an MCVE: Minimal, Complete, and Verifiable 
Example.  See  http://stackoverflow.com/help/mcve for a full description.
--- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at https://groups.google.com/group/sqlalchemy.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sqlalchemy/c54ac24d-933b-4d15-9991-5371bd8a28d3%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to