Dew

Dew vs Raw SQL

Side-by-side comparison of dew queries and raw SQL.

Every dew query maps directly to SQL. Here's a side-by-side comparison so you always know what's being generated.

Simple select

users, err := Users.From(db).
    Where(Users.Name.Eq("Alice")).
    All(ctx)
SELECT * FROM users WHERE users.name = $1
-- args: ["Alice"]

Select with columns

users, err := Users.From(db).
    Select(Users.Name, Users.Email).
    Where(Users.Age.Gte(18)).
    OrderBy(dew.Asc(Users.Name)).
    Limit(10).
    All(ctx)
SELECT users.name, users.email FROM users
WHERE users.age >= $1
ORDER BY users.name ASC
LIMIT 10
-- args: [18]

OR conditions

users, err := Users.From(db).
    Where(dew.Or(
        Users.Role.Eq("admin"),
        Users.Role.Eq("moderator"),
    )).
    All(ctx)
SELECT * FROM users
WHERE (users.role = $1 OR users.role = $2)
-- args: ["admin", "moderator"]

Insert

err := Users.Insert(db).
    Columns(Users.Name, Users.Email).
    Values("Alice", "alice@example.com").
    Values("Bob", "bob@example.com").
    Exec(ctx)
INSERT INTO users (name, email) VALUES ($1, $2), ($3, $4)
-- args: ["Alice", "alice@example.com", "Bob", "bob@example.com"]

Upsert

err := Users.Insert(db).
    Columns(Users.Name, Users.Email).
    Values("Alice", "alice@example.com").
    OnConflict(Users.Email).
    SetUpdate(Users.Name, "Alice Updated").
    Exec(ctx)
INSERT INTO users (name, email) VALUES ($1, $2)
ON CONFLICT (email) DO UPDATE SET name = $3
-- args: ["Alice", "alice@example.com", "Alice Updated"]

Update

err := Users.Update(db).
    Set(Users.Name, "Bob").
    Set(Users.Age, dew.Raw("age + ?", 1)).
    Where(Users.ID.Eq(1)).
    Exec(ctx)
UPDATE users SET name = $1, age = age + $2
WHERE users.id = $3
-- args: ["Bob", 1, 1]

Delete

err := Users.Delete(db).
    Where(Users.Age.Lt(18)).
    Exec(ctx)
DELETE FROM users WHERE users.age < $1
-- args: [18]

Join

users, err := Users.From(db).
    Select(Users.Name, dew.Count(Orders.ID)).
    LeftJoin(Orders, Users.ID, Orders.UserID).
    GroupBy(Users.Name).
    Having(dew.Raw("COUNT(orders.id) > ?", 5)).
    All(ctx)
SELECT users.name, COUNT(orders.id) FROM users
LEFT JOIN orders ON users.id = orders.user_id
GROUP BY users.name
HAVING COUNT(orders.id) > $1
-- args: [5]

Subquery

users, err := Users.From(db).
    Where(Users.ID.InSub(
        Orders.From(db).Select(Orders.UserID).Where(Orders.Total.Gt(100)),
    )).
    All(ctx)
SELECT * FROM users
WHERE users.id IN (
    SELECT orders.user_id FROM orders WHERE orders.total > $1
)
-- args: [100]

JSONB containment

users, err := Users.From(db).
    Where(Users.Profile.Contains(&Profile{"role": "admin"})).
    All(ctx)
SELECT * FROM users
WHERE users.profile @> $1::jsonb
-- args: [{"role":"admin"}]

Transaction

tx, _ := db.BeginTx(ctx, nil)

Users.Insert(tx).
    Columns(Users.Name).
    Values("Alice").
    Exec(ctx)

Users.Update(tx).
    Set(Users.Role, "admin").
    Where(Users.Name.Eq("Alice")).
    Exec(ctx)

tx.Commit()
BEGIN;

INSERT INTO users (name) VALUES ($1);
-- args: ["Alice"]

UPDATE users SET role = $1 WHERE users.name = $2;
-- args: ["admin", "Alice"]

COMMIT;

Dialect differences

The same dew code, different SQL output:

Users.From(db).Where(Users.ID.Eq(1), Users.Name.Eq("Alice")).ToSql()
DialectOutput
PostgreSQLSELECT * FROM users WHERE users.id = $1 AND users.name = $2
MySQLSELECT * FROM users WHERE users.id = ? AND users.name = ?
MSSQLSELECT * FROM users WHERE users.id = @p1 AND users.name = @p2

Same Go code, zero changes. The dialect handles the rest.

On this page