On Feb 2, 2014, at 4:31 PM, Matt Phipps <[email protected]> wrote:

> def _trackable_truckload_details():
>     text = db.text("EXEC ODSQuery.SelectBridgeLoadBoard")
>     cols = [col for col in LoadBoard.__table__.c]
>     cols = map((lambda x: label('ODSQuery_tblLoadBoard_' + x.name, x)), cols)
>     mobile_cols = LoadMobileTracking.load_mobile_tracking_id.property.columns
>     mobile_cols = map((lambda x: label('LoadMobileTracking_' + x.name, x)), 
> cols)
>     cols.extend(mobile_cols)
>     taf = text.columns(*cols)
>     return db.session.query(
>         LoadBoard.load,
>         LoadBoard.orgn_stop,
>         LoadBoard.dest_stop,
>         LoadMobileTracking.load_mobile_tracking_id).from_statement(taf).all()
> 
> 
> Actually, I'm pretty surprised it worked at all before, without the labeling. 
> How did it figure out which result set columns went to which ORM object?

This is because what’s actually going on is more sophisticated than just 
matching up the names.  When the ORM looks for columns in a row, it uses the 
actual Column object to target the column.   If your class is mapped to a table 
“users”, for example, it would look like this:

users = Table(‘users’, metadata, Column(‘id’, Integer), Column(‘name’, String))

# … later

for row in conn.execute(some_orm_statement):
   user_id = row[users.c.id]
   user_name = row[users.c.name]

that is, we aren’t using strings at all.  When the Core select() object (or 
TextAsFrom in this case) is compiled for the backend, all the Column objects it 
SELECTs from are put into an internal collection called the “result_map”, which 
keys the result columns in several ways, including their positional index (0, 
1, 2, ..) as well as the string name the statement knows they’ll have in the 
result set (e.g. the label name in this case) to all the objects that might be 
used to look them up.

So using a label(), that adds another layer onto this.  The label() you create 
from an existing Column still refers to that Column, and we say the Label 
object “proxies” the Column.  if you look in mylabel.proxy_set() you’ll see 
that Column.

So when we generate the result_map, we put as keys *all* of the things that 
each label() is a “proxy” for, including the Column objects that are in our 
mapping.  its this large and awkward dictionary structure I’ve had to stare at 
for many years as I often have to fix new issues that have arisen (such as this 
one).

The result is generated, we link the columns in the cursor.description by 
string name to the string names we know are rendered in the final compiled 
construct, the result set now knows that all the Column/Label objects 
corresponding to “id” are linked to that column and that’s how the lookup 
proceeds.

>  
> I’m committing 2932 in a moment and I’m super really hoping I can put out 
> 0.9.2 today but it’s easy for me to run out of time, but 0.9.2 is definitely 
> due.
> 
> That would be awesome! Incidentally though, would this labeling still work 
> once the fix is in?

all the existing mechanisms are maintained and I’ve just made some of the 
matching logic a bit more liberal here, so should be fine.  It’s all committed 
if you want to try out the git master.

Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to