# Path: tests/benchmarks/benchmark_utils.py
# def benchmark_parallel_funcs(n_iterations, n_parts, *funcs):
#     """ Run the given `funcs` test functions `n_iterations` times.
# 
#     Every function receives the `n` argument and is supposed to do its job `n` times in a loop.
#     This is to reduce the impact of a repeated function call, and to let your tests initialize before they run.
# 
#     Names of those functions are used in displaying results.
#     """
#     return benchmark_parallel(
#         n_iterations,
#         n_parts,
#         **{f.__name__: f for f in funcs})
# 
# Path: tests/models.py
# def get_big_db_for_benchmarks(n_users, n_articles_per_user, n_comments_per_article):
#     # Connect, create tables
#     engine, Session = init_database(autoflush=True)
#     drop_all(engine)
#     create_all(engine)
# 
#     # Fill DB
#     ssn = Session()
#     ssn.begin()
#     ssn.add_all(content_samples_random(n_users, n_articles_per_user, n_comments_per_article))
#     ssn.commit()
# 
#     # Done
#     return engine, Session
# 
# class User(Base):
#     __tablename__ = 'u'
# 
#     id = Column(Integer, primary_key=True)
#     name = Column(String)
#     tags = Column(pg.ARRAY(String))  # ARRAY field
#     age = Column(Integer)
# 
#     # Maps an SQL expression as a column
#     age_in_10 = column_property(age + 10, deferred=True)
# 
#     master_id = Column(ForeignKey('u.id', ondelete='SET NULL'), nullable=True)
#     master = relationship(lambda: User, remote_side=lambda: User.id, foreign_keys=master_id)
# 
#     @property
#     def user_calculated(self):
#         return self.age + 10
# 
#     def __repr__(self):
#         return 'User(id={}, name={!r})'.format(self.id, self.name)
# 
# class Article(Base):
#     __tablename__ = 'a'
# 
#     id = Column(Integer, primary_key=True)
#     uid = Column(Integer, ForeignKey(User.id))
#     title = Column(String)
#     theme = Column(String)
#     data = Column(pg.JSON)  # JSON field
# 
#     user = relationship(User, backref=backref('articles'))
# 
#     @property
#     def calculated(self):
#         return len(self.title) + self.uid
# 
#     @calculated.setter
#     def calculated(self, value):
#         self.title += value
# 
#     @hybrid_property
#     def hybrid(self):
#         return self.id > 10 and self.user.age > 18
# 
#     @hybrid.expression
#     def hybrid(cls):
#         return and_(cls.id > 10, cls.user.has(User.age > 18))
# 
#     def __repr__(self):
#         return 'Article(id={}, uid={!r}, title={!r})'.format(self.id, self.uid, self.title)


from sqlalchemy.orm import selectinload, joinedload
from tests.benchmarks.benchmark_utils import benchmark_parallel_funcs
from tests.models import get_big_db_for_benchmarks, User, Article
to those queries that feed the data to JSON immediately. It's worth doing, but is rather complicated.

The problems with this approach: we'll have to make sure that `@property` fields are included into the results if
they were specified in a projection.
"""



# Init DB
engine, Session = get_big_db_for_benchmarks(n_users=100,
                                            n_articles_per_user=5,
                                            n_comments_per_article=3)

# Prepare
N_REPEATS = 500
ssn = Session()


# Tests
def test_selectinload(n):
    """ Load Users+Articles+Comments, with selectinload() """
    for i in range(n):
        users = ssn.query(User).options(
            selectinload(User.articles).selectinload(Article.comments)
        ).all()


def test_joinedload(n):
    """ Load Users+Articles+Comments, with joinedload() """
    for i in range(n):

# Path: tests/benchmarks/benchmark_utils.py
# def benchmark_parallel_funcs(n_iterations, n_parts, *funcs):
#     """ Run the given `funcs` test functions `n_iterations` times.
# 
#     Every function receives the `n` argument and is supposed to do its job `n` times in a loop.
#     This is to reduce the impact of a repeated function call, and to let your tests initialize before they run.
# 
#     Names of those functions are used in displaying results.
#     """
#     return benchmark_parallel(
#         n_iterations,
#         n_parts,
#         **{f.__name__: f for f in funcs})
# 
# Path: tests/models.py
# def get_big_db_for_benchmarks(n_users, n_articles_per_user, n_comments_per_article):
#     # Connect, create tables
#     engine, Session = init_database(autoflush=True)
#     drop_all(engine)
#     create_all(engine)
# 
#     # Fill DB
#     ssn = Session()
#     ssn.begin()
#     ssn.add_all(content_samples_random(n_users, n_articles_per_user, n_comments_per_article))
#     ssn.commit()
# 
#     # Done
#     return engine, Session
# 
# class User(Base):
#     __tablename__ = 'u'
# 
#     id = Column(Integer, primary_key=True)
#     name = Column(String)
#     tags = Column(pg.ARRAY(String))  # ARRAY field
#     age = Column(Integer)
# 
#     # Maps an SQL expression as a column
#     age_in_10 = column_property(age + 10, deferred=True)
# 
#     master_id = Column(ForeignKey('u.id', ondelete='SET NULL'), nullable=True)
#     master = relationship(lambda: User, remote_side=lambda: User.id, foreign_keys=master_id)
# 
#     @property
#     def user_calculated(self):
#         return self.age + 10
# 
#     def __repr__(self):
#         return 'User(id={}, name={!r})'.format(self.id, self.name)
# 
# class Article(Base):
#     __tablename__ = 'a'
# 
#     id = Column(Integer, primary_key=True)
#     uid = Column(Integer, ForeignKey(User.id))
#     title = Column(String)
#     theme = Column(String)
#     data = Column(pg.JSON)  # JSON field
# 
#     user = relationship(User, backref=backref('articles'))
# 
#     @property
#     def calculated(self):
#         return len(self.title) + self.uid
# 
#     @calculated.setter
#     def calculated(self, value):
#         self.title += value
# 
#     @hybrid_property
#     def hybrid(self):
#         return self.id > 10 and self.user.age > 18
# 
#     @hybrid.expression
#     def hybrid(cls):
#         return and_(cls.id > 10, cls.user.has(User.age > 18))
# 
#     def __repr__(self):
#         return 'Article(id={}, uid={!r}, title={!r})'.format(self.id, self.uid, self.title)


# Path: tests/benchmarks/benchmark_compare_orm_overhead_with_pure_jsonb_output.py
from sqlalchemy.orm import selectinload, joinedload
from tests.benchmarks.benchmark_utils import benchmark_parallel_funcs
from tests.models import get_big_db_for_benchmarks, User, Article

to those queries that feed the data to JSON immediately. It's worth doing, but is rather complicated.

The problems with this approach: we'll have to make sure that `@property` fields are included into the results if
they were specified in a projection.
"""



# Init DB
engine, Session = get_big_db_for_benchmarks(n_users=100,
                                            n_articles_per_user=5,
                                            n_comments_per_article=3)

# Prepare
N_REPEATS = 500
ssn = Session()


# Tests
def test_selectinload(n):
    """ Load Users+Articles+Comments, with selectinload() """
    for i in range(n):
        users = ssn.query(User).options(
            selectinload(User.articles).selectinload(Article.comments)
        ).all()


def test_joinedload(n):
    """ Load Users+Articles+Comments, with joinedload() """
    for i in range(n):

        users = ssn.query(User).options(