Skip to content
Danila Ganchar edited this page Jul 14, 2026 · 56 revisions

Overview

david8 - the next generation Weyland Robot is lightweight Python SQL builder

IDE-friendly

Screenshot-2026-06-16-15-23-40.png

ide.png

Comparison

SQL query from benchmarks. Syntax comparison: pypika, sqlalchemy, david8. 1.9.0b1 results:

Screenshot-2026-07-14-10-34-52.png

Package Size Commits Pull Requests Coverage
david8 size commits PRs Coverage
david8_clickhouse size commits PRs Coverage
david8_duckdb size commits PRs Coverage
david8_postgresql size commits PRs Coverage
pypika size commits PRs Coverage

Query example

from datetime import datetime, timedelta
from david8 import get_default_qb
from david8.expressions import val, desc
from david8.functions import count
from david8.predicates import lt, gt, eq, between

qb = get_default_qb()


class Users:
    @staticmethod
    def last_active():
        end = datetime.now()
        start = end - timedelta(days=10)
        return (
            qb
            .select('*')
            .from_table('users')
            .where(
                between('last_login_day', val(str(start.date())), val(str(end.date()))),
                eq('status', val('active')),
            )
        )

query = (qb
    .with_(
        ('group_a', Users.last_active().where(lt('age', 18), gt('height', 150))),
        ('group_b', Users.last_active().where(gt('age', 30), gt('height', 170))),
    )
    .select(
        count('*').as_('total_users'),
        'age',
        'gender',
        'last_login_day',
    )
    .from_expr(
        qb
        .select('age', 'gender', 'last_login_day')
        .from_table('group_a')
        .union(qb.select('age', 'gender', 'last_login_day').from_table('group_b'))
    )
    .group_by('age', 'gender', 'last_login_day')
    .order_by(desc('total_users', 'last_login_day'))
    .limit(10)
 )


print(query.get_sql())
# WITH group_a AS (
#     SELECT * FROM users
#      WHERE last_login_day BETWEEN '2025-12-07' AND '2025-12-10'
#        AND status = 'active'
#        AND age < %(p1)s
#        AND height > %(p2)s
# ),
# group_b AS (
#     SELECT * FROM users
#      WHERE last_login_day BETWEEN '2025-12-07' AND '2025-12-10'
#        AND status = 'active'
#        AND age > %(p3)s
#        AND height > %(p4)s
# )
# SELECT count(*) AS total_users,
#                    age,
#                    gender,
#                    last_login_day
#   FROM (
#       SELECT age,
#              gender,
#              last_login_day
#         FROM group_a
#        UNION ALL
#       SELECT age, gender, last_login_day
#         FROM group_b
#  )
#   GROUP BY age,
#            gender,
#            last_login_day
#   ORDER BY total_users DESC,
#            last_login_day DESC
#   LIMIT 10
print(query.get_parameters())
# {'p1': 18, 'p2': 150, 'p3': 30, 'p4': 170}

Links

Package Structure

├── core                 # core logic and dialects API
├── functions_pg_duck.py # Deprecated since 1.6.0b1, will be removed in 0.1.0. Use functions.py
# public API
├── cast_types.py        # common types: text, varchar
├── expressions.py       # common tiny sql expressions: desc(), val(), param(), interval()
├── frames.py            # window modes and frames: ROWS, RANGE, CURRENT ROW
├── functions.py         # common functions: lower(), avg(), rank()
├── joins.py             # common join types: left(), right()
├── logical_operators.py # or_(), and_(), xor()
├── param_styles.py      # QMark, Numeric, PyFormat etc
├── predicates.py        # eq(), ne(), between() etc
└── protocols

Clone this wiki locally