Skip to content

BitAspire/jdborm

Repository files navigation

jdborm — Fluent JDBC Query Builder

License: MIT Java 17+

A lightweight, zero-dependency Java library inspired by Drizzle ORM.
Write type-safe SQL queries using fluent method chaining instead of raw string concatenation.

Quick Start

1. Add dependency

Gradle:

repositories {
    mavenCentral()
    maven { url = uri("https://jitpack.io") }
}

dependencies {
    implementation("com.github.BitAspire:jdborm:0.4.1")
}

Maven:

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

<dependency>
    <groupId>com.github.BitAspire</groupId>
    <artifactId>jdborm</artifactId>
    <version>0.4.1</version>
</dependency>

2. Use it

import static com.bitaspire.jdborm.condition.Conditions.*;

JdbORM db = JdbORM.create(dataSource);

// SELECT with conditions and ordering
List<User> users = db.select("id", "name", "email")
    .from("users")
    .where(eq("age", 18).and(gt("score", 100)))
    .orderBy("name")
    .limit(10)
    .execute(User.class);

// Custom RowMapper (no reflection)
List<User> users = db.select("*").from("users")
    .execute((rs, i) -> new User(rs.getLong("id"), rs.getString("name")));

// Scalar result (e.g. count)
Long count = db.select("count(*)").from("users").executeScalar(Long.class);

// INSERT with raw expression + ON CONFLICT
var keys = db.insert("users")
    .set("name", "John")
    .setRaw("created_at", "NOW())
    .onConflictDoNothing()
    .execute();

// Batch INSERT
InsertQuery ins = db.insert("users");
ins.set("name", "Alice").addBatch();
ins.set("name", "Bob").addBatch();
ins.executeBatch();

// UPDATE with raw expression
int affected = db.update("users")
    .set("name", "Jane")
    .setRaw("updated_at", "NOW())
    .where(eq("id", 1))
    .execute();

// DELETE
int deleted = db.delete("users")
    .where(eq("id", 1))
    .execute();

// Transaction
db.inTransaction(tx -> {
    tx.insert("users").set("name", "John").execute();
    tx.update("accounts").set("balance", 100).where(eq("id", 1)).execute();
    return null;
});

// Raw SQL
db.execute("UPDATE users SET name = ? WHERE id = ?", "John", 1);
List<User> users = db.query("SELECT * FROM users WHERE id = ?",
    (rs, i) -> new User(rs.getLong("id"), rs.getString("name")), 1);

Conditions API

Method SQL output Example
eq("col", val) col = ? eq("status", "active")
ne("col", val) col <> ? ne("age", 18)
gt("col", val) col > ? gt("price", 100)
gte("col", val) col >= ? gte("score", 50)
lt("col", val) col < ? lt("age", 21)
lte("col", val) col <= ? lte("rating", 5)
like("col", val) col LIKE ? like("name", "%john%")
in("col", v1, v2) col IN (?, ?) in("id", 1, 2, 3)
between("col", a, b) col BETWEEN ? AND ? between("price", 10, 50)
isNull("col") col IS NULL isNull("deleted_at")
isNotNull("col") col IS NOT NULL isNotNull("email")
not(cond) NOT (cond) not(eq("banned", true))
cond1.and(cond2) cond1 AND cond2 eq("a", 1).and(eq("b", 2))
cond1.or(cond2) cond1 OR cond2 eq("a", 1).or(eq("b", 2))
and(c1, c2, ...) c1 AND c2 AND ... and(eq("a",1), eq("b",2))
or(c1, c2, ...) c1 OR c2 OR ... or(eq("a",1), eq("b",2))
raw("sql") Raw SQL fragment raw("NOW()")

Compound conditions example

where(and(
    eq("status", "active"),
    or(eq("role", "admin"), eq("role", "moderator")),
    not(eq("banned", true))
));

Joins

List<Post> posts = db.select("u.id", "p.title")
    .from("users u")
    .join("posts p", "p.user_id", "u.id")
    .leftJoin("comments c", "c.post_id", "p.id")
    .rightJoin("likes l", "l.post_id", "p.id")
    .execute(Post.class);

Query API overview

Builder Key methods Returns
JdbORM .execute(sql, params), .query(sql, mapper, params), .inTransaction(callback) int, List<T>, T
SelectQuery .from(), .where(), .join(), .orderBy(), .limit(), .offset() List<T> / execute(Class), execute(RowMapper), executeScalar(Class)
InsertQuery .set(), .setRaw(), .onConflict(), .onConflictOnConstraint(), .doNothing(), .doUpdateSet(), .onConflictDoNothing(), .onConflictDoUpdate(), .addBatch() GeneratedKeys, int[]
UpdateQuery .set(), .setRaw(), .where() int (affected rows)
DeleteQuery .where() int (affected rows)

All builders support .toSql() and .getParameters() for debugging.

Features added in v0.4.1

  • Fix InsertQuery.executeBatch() to correctly bind null parameter values via PreparedStatement.setNull()
  • Fix InsertQuery.executeBatch() to use single-row INSERT SQL with addBatch(), preventing "parameter not set" errors on JDBC batch execution
  • Add integration test for batch insert with nullable columns

Features added in v0.4.0

  • ON CONFLICT target API: .onConflict(columns) + .doNothing() / .doUpdateSet(clauses)
  • ON CONFLICT ON CONSTRAINT: .onConflictOnConstraint(name) for named constraints
  • Static helpers: InsertQuery.excluded(col) and InsertQuery.setClause(col, expr)
  • Unified batch columns: batch rows with different column sets now produce correct SQL
  • Deprecated old methods: .onConflictDoNothing().onConflict().doNothing(), .onConflictDoUpdate().onConflict().doUpdateSet()

Features added in v0.3.1

  • addColumnIfNotExists() on AlterTableQuery — safe ADD COLUMN for PostgreSQL and others

Features added in v0.3.0

  • DDL schema management: createTable(), alterTable(), dropTable()
  • truncateTable(), renameTable() for table management
  • createIndex(), dropIndex() for index management
  • Table-level constraints: PRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK
  • IF EXISTS / IF NOT EXISTS and CASCADE support
  • Full type-safe API via Table and Column overloads

Features added in v0.2.1

  • Raw SQL execution (execute(), query(), querySingle())
  • setRaw() for SQL expressions in INSERT/UPDATE (NOW(), counter + 1, etc.)
  • ON CONFLICT DO NOTHING / ON CONFLICT DO UPDATE on INSERT
  • Custom RowMapper on SELECT (no reflection needed)
  • executeScalar() for single-value results
  • Batch INSERT with addBatch() / executeBatch()
  • Transaction API (inTransaction())

AI Assistant Skill

jdborm comes with an AI skill that gives coding assistants deep knowledge of the entire API:

npx jdborm-ai-skill

Run this once in your project to install .agents/skills/jdborm/SKILL.md — your AI will then be able to write correct jdborm queries without being prompted about the API each time.

Build

./gradlew build

Requirements

  • Java 17+
  • No external runtime dependencies

License

MIT

About

jdborm is a lightweight library to write type-safe SQL queries more easily

Topics

Resources

License

Stars

Watchers

Forks

Contributors