diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 0000000..9879e5a
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,42 @@
+name: Documentation
+
+on:
+ release:
+ types: [published]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ build-and-deploy:
+ name: Build and Deploy
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Pages
+ uses: actions/configure-pages@v5
+
+ - name: Build with Jekyll
+ uses: actions/jekyll-build-pages@v1
+ with:
+ source: ./docs
+ destination: ./_site
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 0000000..10962b1
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,21 @@
+name: Lint
+
+on:
+ pull_request:
+ paths:
+ - "docs/**/*.md"
+ - ".markdownlint.yml"
+
+jobs:
+ markdown:
+ name: Validate Markdown
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Lint Markdown
+ uses: DavidAnson/markdownlint-cli2-action@v16
+ with:
+ globs: "docs/**/*.md"
+ config: ".markdownlint.yml"
diff --git a/.markdownlint.yml b/.markdownlint.yml
new file mode 100644
index 0000000..39e5272
--- /dev/null
+++ b/.markdownlint.yml
@@ -0,0 +1,12 @@
+default: true
+MD013: false
+MD022: false
+MD025:
+ front_matter_title: ""
+MD033: false
+MD036: false
+MD041: false
+MD024:
+ siblings_only: true
+MD007:
+ indent: 2
diff --git a/README.md b/README.md
index 919624c..542caae 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,9 @@
# JavaQueryBuilder
+[](https://jitpack.io/#EzFramework/JavaQueryBuilder)
+[](https://github.com/EzFramework/JavaQueryBuilder/packages)
+[](https://codecov.io/gh/EzFramework/JavaQueryBuilder)
+
A lightweight, fluent Java library for building parameterized SQL queries and filtering in-memory data, no runtime dependencies required.
## Features
diff --git a/docs/Gemfile b/docs/Gemfile
new file mode 100644
index 0000000..7359a80
--- /dev/null
+++ b/docs/Gemfile
@@ -0,0 +1,4 @@
+source "https://rubygems.org"
+
+gem "github-pages", group: :jekyll_plugins
+gem "just-the-docs"
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000..01c03d0
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1,63 @@
+title: JavaQueryBuilder
+description: >-
+ A lightweight, fluent Java library for building parameterized SQL queries
+ and filtering in-memory data. No runtime dependencies required.
+
+url: "https://ezframework.github.io"
+baseurl: "/JavaQueryBuilder"
+
+# ── Appearance ────────────────────────────────────────────────────────────────
+color_scheme: javaquerybuilder
+heading_anchors: true
+
+# ── Header links ──────────────────────────────────────────────────────────────
+aux_links:
+ "GitHub":
+ - "https://github.com/EzFramework/JavaQueryBuilder"
+ "JitPack":
+ - "https://jitpack.io/#EzFramework/JavaQueryBuilder"
+
+aux_links_new_tab: true
+
+# ── Navigation ────────────────────────────────────────────────────────────────
+nav_sort: case_insensitive
+nav_external_links:
+ - title: Changelog
+ url: "https://github.com/EzFramework/JavaQueryBuilder/releases"
+ hide_icon: false
+
+# ── Search ────────────────────────────────────────────────────────────────────
+search_enabled: true
+search:
+ heading_level: 2
+ previews: 3
+ preview_words_before: 5
+ preview_words_after: 10
+ tokenizer_separator: /[\s/]+/
+
+# ── Footer ────────────────────────────────────────────────────────────────────
+back_to_top: true
+back_to_top_text: "Back to top"
+
+footer_content: >-
+ Copyright © 2024–2026 Gyvex.
+ Distributed under the
+ MIT License.
+
+# ── Kramdown ──────────────────────────────────────────────────────────────────
+kramdown:
+ syntax_highlighter_opts:
+ block:
+ line_numbers: false
+
+# ── Plugins ───────────────────────────────────────────────────────────────────
+plugins:
+ - jekyll-remote-theme
+ - jekyll-seo-tag
+
+# ── Build exclusions ──────────────────────────────────────────────────────────
+exclude:
+ - Gemfile
+ - Gemfile.lock
+
+remote_theme: just-the-docs/just-the-docs
diff --git a/docs/_sass/color_schemes/javaquerybuilder.scss b/docs/_sass/color_schemes/javaquerybuilder.scss
new file mode 100644
index 0000000..15a9e01
--- /dev/null
+++ b/docs/_sass/color_schemes/javaquerybuilder.scss
@@ -0,0 +1,42 @@
+// JavaQueryBuilder — dark/blue/white color scheme for just-the-docs
+//
+// Palette:
+// Background #141414 (body)
+// Surface #1c1c1c (sidebar, cards)
+// Elevated #222222 (code blocks, search, table rows)
+// Border #2e2e2e
+// Text #d0d0d0 (body) / #ffffff (headings)
+// Accent #4d9de0 (blue — links, nav highlight, buttons)
+// Accent dim #3a7bbf (hover state)
+
+$color-scheme: dark;
+
+// ── Surfaces ─────────────────────────────────────────────────────────────────
+$body-background-color: #141414;
+$sidebar-color: #1c1c1c;
+$feedback-color: #181818;
+
+// ── Typography ────────────────────────────────────────────────────────────────
+$body-text-color: #d0d0d0;
+$body-heading-color: #ffffff;
+
+// ── Links & accent ───────────────────────────────────────────────────────────
+$link-color: #4d9de0;
+$btn-primary-color: #4d9de0;
+
+// ── Borders ───────────────────────────────────────────────────────────────────
+$border-color: #2e2e2e;
+
+// ── Code ──────────────────────────────────────────────────────────────────────
+$code-background-color: #222222;
+
+// ── Tables ────────────────────────────────────────────────────────────────────
+$table-background-color: #1a1a1a;
+
+// ── Search ────────────────────────────────────────────────────────────────────
+$search-background-color: #222222;
+$search-foreground-color: #c0c0c0;
+$search-border-color: #333333;
+
+// ── Buttons ───────────────────────────────────────────────────────────────────
+$base-button-color: #252525;
diff --git a/docs/api-reference.md b/docs/api-reference.md
new file mode 100644
index 0000000..3558521
--- /dev/null
+++ b/docs/api-reference.md
@@ -0,0 +1,330 @@
+---
+title: API Reference
+nav_order: 10
+description: "Complete public method tables for every class and interface in JavaQueryBuilder"
+---
+
+# API Reference
+{: .no_toc }
+
+## Table of contents
+{: .no_toc .text-delta }
+
+1. TOC
+{:toc}
+
+---
+
+## builder
+
+### `QueryBuilder`
+
+Main entry point for SELECT queries and static gateway to DML builders.
+
+**Static factory methods**
+
+| Method | Returns | Description |
+|--------|---------|-------------|
+| `insert()` | `InsertBuilder` | New `InsertBuilder` |
+| `insertInto(String table)` | `InsertBuilder` | New `InsertBuilder` pre-set to `table` |
+| `update()` | `UpdateBuilder` | New `UpdateBuilder` |
+| `update(String table)` | `UpdateBuilder` | New `UpdateBuilder` pre-set to `table` |
+| `delete()` | `DeleteBuilder` | New `DeleteBuilder` |
+| `deleteFrom(String table)` | `DeleteBuilder` | New `DeleteBuilder` pre-set to `table` |
+| `createTable()` | `CreateBuilder` | New `CreateBuilder` |
+| `createTable(String table)` | `CreateBuilder` | New `CreateBuilder` pre-set to `table` |
+
+**SELECT builder methods**
+
+| Method | Returns | Description |
+|--------|---------|-------------|
+| `from(String table)` | `QueryBuilder` | Set source table |
+| `select(String... columns)` | `QueryBuilder` | Add columns to SELECT clause; omit for `SELECT *` |
+| `distinct()` | `QueryBuilder` | Add `DISTINCT` to SELECT |
+| `whereEquals(col, val)` | `QueryBuilder` | `WHERE col = ?` (AND) |
+| `orWhereEquals(col, val)` | `QueryBuilder` | `WHERE col = ?` (OR) |
+| `whereNotEquals(col, val)` | `QueryBuilder` | `WHERE col != ?` (AND) |
+| `whereGreaterThan(col, val)` | `QueryBuilder` | `WHERE col > ?` (AND) |
+| `whereGreaterThanOrEquals(col, val)` | `QueryBuilder` | `WHERE col >= ?` (AND) |
+| `whereLessThan(col, val)` | `QueryBuilder` | `WHERE col < ?` (AND) |
+| `whereLessThanOrEquals(col, val)` | `QueryBuilder` | `WHERE col <= ?` (AND) |
+| `whereLike(col, String val)` | `QueryBuilder` | `WHERE col LIKE ?` (AND) |
+| `whereNotLike(col, String val)` | `QueryBuilder` | `WHERE col NOT LIKE ?` (AND) |
+| `whereNull(col)` | `QueryBuilder` | `WHERE col IS NULL` (AND) |
+| `whereNotNull(col)` | `QueryBuilder` | `WHERE col IS NOT NULL` (AND) |
+| `whereExists(col)` | `QueryBuilder` | `WHERE col IS NOT NULL` (AND) |
+| `whereIn(col, List>)` | `QueryBuilder` | `WHERE col IN (...)` (AND) |
+| `whereNotIn(col, List>)` | `QueryBuilder` | `WHERE col NOT IN (...)` (AND) |
+| `whereBetween(col, a, b)` | `QueryBuilder` | `WHERE col BETWEEN ? AND ?` (AND) |
+| `whereInSubquery(col, Query)` | `QueryBuilder` | `WHERE col IN (SELECT ...)` (AND) |
+| `whereEqualsSubquery(col, Query)` | `QueryBuilder` | `WHERE col = (SELECT ...)` (AND) |
+| `whereExistsSubquery(Query)` | `QueryBuilder` | `WHERE EXISTS (SELECT ...)` (AND) |
+| `whereNotExistsSubquery(Query)` | `QueryBuilder` | `WHERE NOT EXISTS (SELECT ...)` (AND) |
+| `fromSubquery(Query, String alias)` | `QueryBuilder` | Replace `FROM` with a derived-table subquery |
+| `joinSubquery(Query, String alias, String on)` | `QueryBuilder` | `INNER JOIN (SELECT ...) AS alias ON ...` |
+| `selectSubquery(Query, String alias)` | `QueryBuilder` | Add `(SELECT ...) AS alias` to SELECT list |
+| `groupBy(String... columns)` | `QueryBuilder` | Add `GROUP BY` columns |
+| `havingRaw(String clause)` | `QueryBuilder` | Set raw `HAVING` SQL fragment |
+| `orderBy(String col, boolean asc)` | `QueryBuilder` | Add `ORDER BY` column; `true` = ASC |
+| `limit(int n)` | `QueryBuilder` | Set `LIMIT` |
+| `offset(int n)` | `QueryBuilder` | Set `OFFSET` |
+| `build()` | `Query` | Build a `Query` object (no SQL rendered yet) |
+| `buildSql()` | `SqlResult` | Render SELECT using table set via `from()`, standard dialect |
+| `buildSql(String table)` | `SqlResult` | Render SELECT for explicit `table`, standard dialect |
+| `buildSql(String table, SqlDialect)` | `SqlResult` | Render SELECT for explicit `table` and dialect |
+
+---
+
+### `SelectBuilder`
+
+Lower-level SELECT builder that produces `SqlResult` directly (no `Query` intermediary).
+
+| Method | Returns | Description |
+|--------|---------|-------------|
+| `from(String table)` | `SelectBuilder` | Set source table |
+| `select(String... columns)` | `SelectBuilder` | Add SELECT columns |
+| `distinct()` | `SelectBuilder` | Add `DISTINCT` |
+| `whereEquals(col, val)` | `SelectBuilder` | `WHERE col = ?` |
+| `whereIn(col, List>)` | `SelectBuilder` | `WHERE col IN (...)` |
+| `whereLike(col, String val)` | `SelectBuilder` | `WHERE col LIKE ?` |
+| `groupBy(String... columns)` | `SelectBuilder` | Add `GROUP BY` |
+| `orderBy(String col, boolean asc)` | `SelectBuilder` | Add `ORDER BY` |
+| `limit(int n)` | `SelectBuilder` | Set `LIMIT` |
+| `offset(int n)` | `SelectBuilder` | Set `OFFSET` |
+| `build(SqlDialect)` | `SqlResult` | Render SELECT with given dialect |
+
+---
+
+### `InsertBuilder`
+
+| Method | Returns | Description |
+|--------|---------|-------------|
+| `into(String table)` | `InsertBuilder` | Set target table |
+| `value(String col, Object val)` | `InsertBuilder` | Add a column/value pair |
+| `build()` | `SqlResult` | Render with standard dialect |
+| `build(SqlDialect)` | `SqlResult` | Render with specified dialect |
+
+---
+
+### `UpdateBuilder`
+
+| Method | Returns | Description |
+|--------|---------|-------------|
+| `table(String table)` | `UpdateBuilder` | Set target table |
+| `set(String col, Object val)` | `UpdateBuilder` | Add a SET pair |
+| `whereEquals(col, val)` | `UpdateBuilder` | `WHERE col = ?` (AND) |
+| `orWhereEquals(col, val)` | `UpdateBuilder` | `WHERE col = ?` (OR) |
+| `whereGreaterThanOrEquals(col, int val)` | `UpdateBuilder` | `WHERE col >= ?` (AND) |
+| `build()` | `SqlResult` | Render with standard dialect |
+| `build(SqlDialect)` | `SqlResult` | Render with specified dialect |
+
+---
+
+### `DeleteBuilder`
+
+| Method | Returns | Description |
+|--------|---------|-------------|
+| `from(String table)` | `DeleteBuilder` | Set target table |
+| `whereEquals(col, val)` | `DeleteBuilder` | `WHERE col = ?` (AND) |
+| `whereNotEquals(col, val)` | `DeleteBuilder` | `WHERE col != ?` (AND) |
+| `whereGreaterThan(col, val)` | `DeleteBuilder` | `WHERE col > ?` (AND) |
+| `whereGreaterThanOrEquals(col, val)` | `DeleteBuilder` | `WHERE col >= ?` (AND) |
+| `whereLessThan(col, val)` | `DeleteBuilder` | `WHERE col < ?` (AND) |
+| `whereLessThanOrEquals(col, val)` | `DeleteBuilder` | `WHERE col <= ?` (AND) |
+| `whereIn(col, List>)` | `DeleteBuilder` | `WHERE col IN (...)` (AND); throws `IllegalArgumentException` if list is null/empty |
+| `whereNotIn(col, List>)` | `DeleteBuilder` | `WHERE col NOT IN (...)` (AND); throws `IllegalArgumentException` if list is null/empty |
+| `whereBetween(col, from, to)` | `DeleteBuilder` | `WHERE col BETWEEN ? AND ?` (AND) |
+| `build()` | `SqlResult` | Render with standard dialect |
+| `build(SqlDialect)` | `SqlResult` | Render with specified dialect |
+
+---
+
+### `CreateBuilder`
+
+| Method | Returns | Description |
+|--------|---------|-------------|
+| `table(String name)` | `CreateBuilder` | Set table name |
+| `column(String name, String sqlType)` | `CreateBuilder` | Add column definition |
+| `primaryKey(String name)` | `CreateBuilder` | Declare a primary key column |
+| `ifNotExists()` | `CreateBuilder` | Add `IF NOT EXISTS` |
+| `build()` | `SqlResult` | Render; throws `IllegalStateException` if table or columns are missing |
+| `build(SqlDialect)` | `SqlResult` | Render with specified dialect |
+
+---
+
+## condition
+
+### `Operator`
+
+Enum of comparison operators. See [Conditions](conditions) for the full table.
+
+| Constant | SQL |
+|----------|-----|
+| `EQ` | `= ?` |
+| `NEQ` | `!= ?` |
+| `GT` | `> ?` |
+| `GTE` | `>= ?` |
+| `LT` | `< ?` |
+| `LTE` | `<= ?` |
+| `LIKE` | `LIKE ?` |
+| `NOT_LIKE` | `NOT LIKE ?` |
+| `EXISTS` | `IS NOT NULL` |
+| `IS_NULL` | `IS NULL` |
+| `IS_NOT_NULL` | `IS NOT NULL` |
+| `IN` | `IN (...)` |
+| `NOT_IN` | `NOT IN (...)` |
+| `BETWEEN` | `BETWEEN ? AND ?` |
+| `EXISTS_SUBQUERY` | `EXISTS (SELECT ...)` |
+| `NOT_EXISTS_SUBQUERY` | `NOT EXISTS (SELECT ...)` |
+
+---
+
+### `Condition`
+
+| Member | Description |
+|--------|-------------|
+| `Condition(Operator op, Object value)` | Create a condition; `value` may be `null` |
+| `getOperator()` | Returns the `Operator` |
+| `getValue()` | Returns the comparison value (`null`, scalar, `List>`, or `Query`) |
+| `matches(Map map, String key)` | Evaluate against an in-memory attribute map |
+
+---
+
+### `ConditionEntry`
+
+| Member | Description |
+|--------|-------------|
+| `ConditionEntry(String col, Condition cond, Connector connector)` | Create a condition entry |
+| `getColumn()` | Column name (`null` for EXISTS-subquery conditions) |
+| `getCondition()` | The wrapped `Condition` |
+| `getConnector()` | `AND` or `OR` |
+
+---
+
+### `Connector`
+
+| Constant | SQL keyword |
+|----------|-------------|
+| `AND` | `AND` |
+| `OR` | `OR` |
+
+---
+
+## query
+
+### `Query`
+
+Immutable data holder produced by `QueryBuilder.build()`. All fields have
+getters and setters; setters are used exclusively by the builders.
+
+| Getter | Type | Description |
+|--------|------|-------------|
+| `getTable()` | `String` | Source table name |
+| `getSelectColumns()` | `List` | Columns in SELECT clause; empty = `SELECT *` |
+| `isDistinct()` | `boolean` | Whether `DISTINCT` is active |
+| `getConditions()` | `List` | WHERE conditions |
+| `getGroupBy()` | `List` | GROUP BY columns |
+| `getHavingRaw()` | `String` | Raw HAVING fragment |
+| `getOrderBy()` | `List` | ORDER BY columns |
+| `getOrderByAsc()` | `List` | True = ASC per ORDER BY entry |
+| `getLimit()` | `Integer` | LIMIT value; `0` or negative = no limit |
+| `getOffset()` | `Integer` | OFFSET value |
+| `getFromSubquery()` | `Query` | FROM-derived subquery; `null` for plain table |
+| `getFromAlias()` | `String` | Alias for FROM subquery |
+| `getJoins()` | `List` | JOIN clauses |
+| `getSelectSubqueries()` | `List` | Scalar SELECT subquery items |
+
+---
+
+### `JoinClause`
+
+| Member | Description |
+|--------|-------------|
+| `JoinClause(Type, String table, String on)` | Plain-table join |
+| `JoinClause(Type, Query subquery, String alias, String on)` | Subquery (derived-table) join |
+| `getType()` | `JoinClause.Type` — `INNER`, `LEFT`, `RIGHT`, or `CROSS` |
+| `getTable()` | Table name for plain-table join; `null` for subquery join |
+| `getSubquery()` | Subquery for derived-table join; `null` for plain-table join |
+| `getAlias()` | Alias for derived-table join |
+| `getOnCondition()` | Raw SQL `ON` fragment |
+
+---
+
+### `ScalarSelectItem`
+
+| Member | Description |
+|--------|-------------|
+| `ScalarSelectItem(Query subquery, String alias)` | Create a scalar SELECT item |
+| `getSubquery()` | The subquery to embed |
+| `getAlias()` | Column alias in SELECT clause |
+
+---
+
+### `QueryableStorage`
+
+Functional interface for in-memory filtering.
+
+```java
+@FunctionalInterface
+public interface QueryableStorage {
+ List query(Query q) throws Exception;
+}
+```
+
+---
+
+## sql
+
+### `SqlDialect`
+
+| Member | Description |
+|--------|-------------|
+| `STANDARD` | ANSI SQL — no identifier quoting |
+| `MYSQL` | MySQL — back-tick quoting; DELETE LIMIT supported |
+| `SQLITE` | SQLite — double-quote quoting; DELETE LIMIT supported |
+| `render(Query)` | Render a SELECT query to `SqlResult` |
+| `renderDelete(Query)` | Render a DELETE query to `SqlResult` |
+
+---
+
+### `SqlResult`
+
+| Method | Returns | Description |
+|--------|---------|-------------|
+| `getSql()` | `String` | Rendered SQL with `?` placeholders |
+| `getParameters()` | `List