Skip to content

Instantly share code, notes, and snippets.

@aodag
Last active August 29, 2015 14:19
Show Gist options
  • Save aodag/ab3c3f0f9fff3eb0ef0f to your computer and use it in GitHub Desktop.
Save aodag/ab3c3f0f9fff3eb0ef0f to your computer and use it in GitHub Desktop.
filter内で使いたいhybrid_methodをQueryオブジェクトのメソッドのようにして流すアイディアの検討
from sqlalchemy.sql import func
def query_maker(session, cls):
query = session.query(cls)
return Adapter(query, cls)
def faster_count_query(query):
count_q = query.statement.with_only_columns([func.count()]).order_by(None)
return query.session.execute(count_q).scalar()
class QueryFactory(object):
def __init__(self, session):
self.session = session
def __call__(self, cls):
return query_maker(self.session, cls)
class Adapter(object):
def __init__(self, query, cls):
self.query = query
self.cls = cls
def __getattr__(self, name):
attr = getattr(self.cls, name)
return QueryWrapper(self.query,
self.cls,
attr)
def __iter__(self):
return iter(self.query)
def __len__(self):
return faster_count_query(self.query)
class QueryWrapper(object):
def __init__(self, query, cls, attr):
self.query = query
self.cls = cls
self.attr = attr
def __call__(self, *args, **kwargs):
query = self.query.filter(
self.attr(*args, **kwargs))
return Adapter(query, self.cls)
def __getattr__(self, name):
query = self.query.filter(self.attr)
attr = getattr(self.cls, name)
return QueryWrapper(query,
self.cls,
attr)
def __iter__(self):
query = self.query.filter(self.attr)
return iter(query)
def __len__(self):
query = self.query.filter(self.attr)
return faster_count_query(query)
from sqlalchemy import (
create_engine,
Column,
Integer,
)
from sqlalchemy.orm import (
sessionmaker,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
Base = declarative_base()
Session = sessionmaker()
class X(Base):
__tablename__ = 'x'
id = Column(Integer, primary_key=True)
value = Column(Integer)
@hybrid_property
def zero(self):
return self.value == 0
@hybrid_method
def greater_than(self, value):
return self.value > value
@hybrid_method
def less_than(self, value):
return self.value < value
engine = create_engine('sqlite:///', echo=True)
Session.configure(bind=engine)
Base.metadata.create_all(bind=engine)
session = Session()
for i in range(1000):
x = X(value=i)
session.add(x)
session.flush()
from adapter import query_maker
print(list(
query_maker(session, X).zero
# session.query(X).filter(X.zero)
))
print(list(
query_maker(session, X).greater_than(100)
# session.query(X).filter(X.greater_than(100))
))
print(list(
query_maker(session, X)
.greater_than(100)
.less_than(200)
# session.query(X).filter(X.greater_than(100)).filter(X.less_than(200))
))
print(len(
query_maker(session, X).zero
))
print(len(
query_maker(session, X).greater_than(100)
))
print(len(
query_maker(session, X)
.greater_than(100)
.less_than(200)
))
print(
session.query(X)
.filter(X.greater_than(100))
.filter(X.less_than(200)).count()
# this provides couting to wrapped subquery
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment