4 ms·
I've never been a fan of Rails' hieroglyphics. "The query is the one you’d hope for" - why do we need to "hope", when the ORM could just allow you to use rela
by zzzeek 14y ago
I've never been a fan of Rails' hieroglyphics. "The query is the one you’d hope for" - why do we need to "hope", when the ORM could just allow you to use relational concepts directly ? Here is SQLAlchemy's much less exciting version of what I see here for "merge", just use a hybrid (sorry, we have more verbose config, due to explicit is better than implicit):
from sqlalchemy import Column, Integer, String, ForeignKey, Enum
from sqlalchemy.orm import Session, relationship, backref
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.ext.hybrid import hybrid_property
class Base(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()
Base = declarative_base(cls=Base)
class SurrogatePK(object):
id = Column(Integer, primary_key=True)
class Article(SurrogatePK, Base):
headline = Column(String)
@property
def users(self):
return self.collaborations.join("user").with_entities(User)
class User(SurrogatePK, Base):
name = Column(String)
class Collaboration(Base):
article_id = Column(ForeignKey('article.id'),
primary_key=True)
user_id = Column(ForeignKey('user.id'),
primary_key=True)
role = Column(Enum('editor', 'author'))
user = relationship("User", backref="collaborations")
article = relationship("Article",
backref=backref("collaborations", lazy="dynamic"))
@hybrid_property
def editorial(self):
return self.role == 'editor'
sess = Session()
some_article = Article(id=5)
sess.add(some_article)
print some_article.users.filter(Collaboration.editorial)
you get the same "one line, DRY" calling style at the end and equivalent SQL:
SELECT "user".id AS user_id, "user".name AS user_name
FROM collaboration JOIN "user" ON "user".id = collaboration.user_id
WHERE :param_1 = collaboration.article_id AND collaboration.role = :role_1
- ben_h 14y agoHope was definitely a bad choice of word. By that I meant, the sort of tight query you'd hope an ORM would deliver. Anyhow, it's a matter of taste, but what may appear at first as hieroglyphics actually is straightforward. It's just that concision here means some packed meaning and some assumed knowledge, so you have to know how to read it. In this case, that's an easy trade-off for me. I'm not familiar with SQLAlchemy, so I find your example equally hard to read, compounded by there being much more code to spelunk through to understand. Different strokes and all that, though. There's room for plenty of frameworks :)
- zzzeek 14y agoIt's just a little friendly/competitive poke! Don't take it seriously, I just couldn't resist. I mostly wanted to demonstrate that the functionality of Rails' merge() can be considered in other ways that are just as succinct.
- sirn 14y ago> I'm not familiar with SQLAlchemy, so I find your example equally hard to read, compounded by there being much more code to spelunk through to understand. If you remove few column definition and setup code, it actually boils down to just: class Article(ArticleColumns): @property def users(self) return self.collaborations.join("user").with_entities(User) class User(UserColumns): pass class Collaboration(CollaborationColumns): user = relationship("User", backref="collaborations") article = relationship("Article", backref=backref("collaborations", lazy="dynamic")) @hybrid_property def editorial(self): return self.role == 'editor' In which you can now do some_article.users.filter(Collaboration.editorial) which generates similar SQL query as #merge.
- xentronium 14y ago> when the ORM could just allow you to use relational concepts directly There is a database toolkit in ruby-land that allows you do just that! It's called Sequel. I've built an example, which I deliberately kept as bare-bones and explicit as possible: https://gist.github.com/1aa977a63b7d6a727497 https://gist.github.com/1aa977a63b7d6a727497 You can also build something similar on top of ARel which backs ActiveRecord.
- sirn 14y agoActually Sequel (and ARel) is more like SQLAlchemy's SQL Expression Language[1] than the SQLAlchemy ORM itself. [1]: http://docs.sqlalchemy.org/en/latest/core/tutorial.html http://docs.sqlalchemy.org/en/latest/core/tutorial.html