Re: [Sqlalchemy-tickets] [sqlalchemy] #2824: Add ability to query column sets as one entity
Brought to you by:
zzzeek
|
From: sqlalchemy <mi...@zz...> - 2013-09-16 17:10:46
|
#2824: Add ability to query column sets as one entity
-----------------------------------+------------------------------------
Reporter: vmagamedov | Owner: zzzeek
Type: enhancement | Status: new
Priority: medium | Milestone: 0.9.xx
Component: orm | Severity: no triage selected yet
Resolution: | Keywords:
Progress State: not decided upon |
-----------------------------------+------------------------------------
Comment (by vmagamedov):
This is what I'm doing right now:) I've just implemented this in more
general way (not only for the case when we query single entity, for
example {{{session.query(Product.id, product_struct, ...)}}}).
Here is my implementation:
{{{#!python
def _obj_getter(struct, i, count):
return lambda row: struct.from_row(row[i:i+count])
def _label_getter(i):
return lambda row: row._labels[i]
_none_getter = lambda row: None
def _expand_entities(entity):
return entity.columns if isinstance(entity, Construct) else (entity,)
class Query(orm.Query):
def _add_value_extractors(self, start_from, entities):
i = start_from
for entity in entities:
if isinstance(entity, Construct):
count = len(entity.columns)
self._value_extractors.append(_obj_getter(entity, i,
count))
self._label_extractors.append(_none_getter)
i += count
else:
self._value_extractors.append(itemgetter(i))
self._label_extractors.append(_label_getter(i))
i += 1
def _set_entities(self, entities, entity_wrapper=None):
self._value_extractors = []
self._label_extractors = []
expanded_entities = tuple(chain(*(imap(_expand_entities,
entities))))
super(Query, self)._set_entities(expanded_entities,
entity_wrapper)
self._add_value_extractors(0, entities)
def add_struct(self, struct):
query = super(Query, self).add_columns(*struct.columns)
query._add_value_extractors(len(self._entities), [struct])
return query
def add_entity(self, entity, alias=None):
query = super(Query, self).add_entity(entity, alias)
query._add_value_extractors(len(self._entities), [entity])
return query
def add_columns(self, *columns):
query = super(Query, self).add_columns(*columns)
query._add_value_extractors(len(self._entities), columns)
return query
def instances(self, *args, **kwargs):
contains_struct = _none_getter in self._label_extractors
single_struct = contains_struct and len(self._value_extractors) ==
1
gen = super(Query, self).instances(*args, **kwargs)
if single_struct:
for row in gen:
yield self._value_extractors[0](row)
elif contains_struct:
for row in gen:
yield NamedTuple([ext(row) for ext in
self._value_extractors],
[ext(row) for ext in
self._label_extractors])
else:
for row in gen:
yield row
}}}
But how I can convince someone else to use this approach if it requires
these quirks? An ideal way is to be able to query such structures with
original Query and Session, without extra setup. I hope this are not very
selfish statements:)
--
Ticket URL: <http://www.sqlalchemy.org/trac/ticket/2824#comment:2>
sqlalchemy <http://www.sqlalchemy.org/>
The Database Toolkit for Python
|