Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,13 @@ Guides for evaluating Storm and transitioning from other frameworks.

Storm works with any JDBC-compatible database. Dialect packages provide optimized support for:

[![Oracle](https://img.shields.io/badge/Oracle-F80000?style=for-the-badge&logo=oracle&logoColor=white)](https://www.oracle.com/database/)
[![SQL Server](https://img.shields.io/badge/SQL%20Server-CC2927?style=for-the-badge&logo=microsoftsqlserver&logoColor=white)](https://www.microsoft.com/sql-server)
[![PostgreSQL](https://img.shields.io/badge/PostgreSQL-336791?style=for-the-badge&logo=postgresql&logoColor=white)](https://www.postgresql.org/)
[![MySQL](https://img.shields.io/badge/MySQL-4479A1?style=for-the-badge&logo=mysql&logoColor=white)](https://www.mysql.com/)
[![MariaDB](https://img.shields.io/badge/MariaDB-003545?style=for-the-badge&logo=mariadb&logoColor=white)](https://mariadb.org/)
[![Oracle](https://img.shields.io/badge/Oracle-F80000?style=for-the-badge&logo=oracle&logoColor=white)](https://www.oracle.com/database/)
[![SQL Server](https://img.shields.io/badge/SQL%20Server-CC2927?style=for-the-badge&logo=microsoftsqlserver&logoColor=white)](https://www.microsoft.com/sql-server)
[![SQLite](https://img.shields.io/badge/SQLite-003B57?style=for-the-badge&logo=sqlite&logoColor=white)](https://www.sqlite.org/)
[![H2](https://img.shields.io/badge/H2-0000bb?style=for-the-badge&logoColor=white)](https://h2database.com/)

## Requirements

Expand Down
72 changes: 34 additions & 38 deletions docs/ai.md

Large diffs are not rendered by default.

109 changes: 85 additions & 24 deletions docs/dialects.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ Storm works with any JDBC-compatible database using standard SQL. However, datab

| | Database | Dialect Package | Key Features |
|---|----------|-----------------|--------------|
| ![Oracle](https://img.shields.io/badge/Oracle-F80000?logo=oracle&logoColor=white) | Oracle | `storm-oracle` | Merge (`MERGE INTO`), sequences |
| ![SQL Server](https://img.shields.io/badge/SQL_Server-CC2927?logo=microsoftsqlserver&logoColor=white) | MS SQL Server | `storm-mssqlserver` | Merge (`MERGE INTO`), identity columns |
| ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql&logoColor=white) | PostgreSQL | `storm-postgresql` | Upsert (`ON CONFLICT`), JSONB, arrays |
| ![MySQL](https://img.shields.io/badge/MySQL-4479A1?logo=mysql&logoColor=white) | MySQL | `storm-mysql` | Upsert (`ON DUPLICATE KEY`), JSON |
| ![MariaDB](https://img.shields.io/badge/MariaDB-003545?logo=mariadb&logoColor=white) | MariaDB | `storm-mariadb` | Upsert (`ON DUPLICATE KEY`), JSON |
| ![Oracle](https://img.shields.io/badge/Oracle-F80000?logo=oracle&logoColor=white) | Oracle | `storm-oracle` | Merge (`MERGE INTO`), sequences |
| ![SQL Server](https://img.shields.io/badge/SQL_Server-CC2927?logo=microsoftsqlserver&logoColor=white) | MS SQL Server | `storm-mssqlserver` | Merge (`MERGE INTO`), identity columns |
| ![H2](https://img.shields.io/badge/H2-0000bb?logoColor=white) | H2 | Built-in | Testing and development (no extra dependency) |
| ![SQLite](https://img.shields.io/badge/SQLite-003B57?logo=sqlite&logoColor=white) | SQLite | `storm-sqlite` | Upsert (`ON CONFLICT`), file-based storage |
| ![H2](https://img.shields.io/badge/H2-0000bb?logoColor=white) | H2 | `storm-h2` | Merge (`MERGE INTO`), sequences, native UUID |

## Installation

Expand All @@ -23,6 +24,22 @@ Add the dialect dependency for your database. Dialects are runtime-only dependen
### Maven

```xml
<!-- Oracle -->
<dependency>
<groupId>st.orm</groupId>
<artifactId>storm-oracle</artifactId>
<version>1.11.0</version>
<scope>runtime</scope>
</dependency>

<!-- MS SQL Server -->
<dependency>
<groupId>st.orm</groupId>
<artifactId>storm-mssqlserver</artifactId>
<version>1.11.0</version>
<scope>runtime</scope>
</dependency>

<!-- PostgreSQL -->
<dependency>
<groupId>st.orm</groupId>
Expand All @@ -47,18 +64,18 @@ Add the dialect dependency for your database. Dialects are runtime-only dependen
<scope>runtime</scope>
</dependency>

<!-- Oracle -->
<!-- SQLite -->
<dependency>
<groupId>st.orm</groupId>
<artifactId>storm-oracle</artifactId>
<artifactId>storm-sqlite</artifactId>
<version>1.11.0</version>
<scope>runtime</scope>
</dependency>

<!-- MS SQL Server -->
<!-- H2 -->
<dependency>
<groupId>st.orm</groupId>
<artifactId>storm-mssqlserver</artifactId>
<artifactId>storm-h2</artifactId>
<version>1.11.0</version>
<scope>runtime</scope>
</dependency>
Expand All @@ -67,6 +84,12 @@ Add the dialect dependency for your database. Dialects are runtime-only dependen
### Gradle (Groovy DSL)

```groovy
// Oracle
runtimeOnly 'st.orm:storm-oracle:1.11.0'

// MS SQL Server
runtimeOnly 'st.orm:storm-mssqlserver:1.11.0'

// PostgreSQL
runtimeOnly 'st.orm:storm-postgresql:1.11.0'

Expand All @@ -76,16 +99,22 @@ runtimeOnly 'st.orm:storm-mysql:1.11.0'
// MariaDB
runtimeOnly 'st.orm:storm-mariadb:1.11.0'

// Oracle
runtimeOnly 'st.orm:storm-oracle:1.11.0'
// SQLite
runtimeOnly 'st.orm:storm-sqlite:1.11.0'

// MS SQL Server
runtimeOnly 'st.orm:storm-mssqlserver:1.11.0'
// H2
runtimeOnly 'st.orm:storm-h2:1.11.0'
```

### Gradle (Kotlin DSL)

```kotlin
// Oracle
runtimeOnly("st.orm:storm-oracle:1.11.0")

// MS SQL Server
runtimeOnly("st.orm:storm-mssqlserver:1.11.0")

// PostgreSQL
runtimeOnly("st.orm:storm-postgresql:1.11.0")

Expand All @@ -95,11 +124,11 @@ runtimeOnly("st.orm:storm-mysql:1.11.0")
// MariaDB
runtimeOnly("st.orm:storm-mariadb:1.11.0")

// Oracle
runtimeOnly("st.orm:storm-oracle:1.11.0")
// SQLite
runtimeOnly("st.orm:storm-sqlite:1.11.0")

// MS SQL Server
runtimeOnly("st.orm:storm-mssqlserver:1.11.0")
// H2
runtimeOnly("st.orm:storm-h2:1.11.0")
```

## Automatic Detection
Expand All @@ -116,11 +145,13 @@ Upsert operations are the primary reason most applications need a dialect. Witho

| Database | SQL Strategy | Conflict Detection |
|----------|--------------|--------------------|
| Oracle | `MERGE INTO ...` | Explicit match conditions |
| MS SQL Server | `MERGE INTO ...` | Explicit match conditions |
| PostgreSQL | `INSERT ... ON CONFLICT DO UPDATE` | Targets a specific unique constraint or index |
| MySQL | `INSERT ... ON DUPLICATE KEY UPDATE` | Primary key or any unique constraint |
| MariaDB | `INSERT ... ON DUPLICATE KEY UPDATE` | Primary key or any unique constraint |
| Oracle | `MERGE INTO ...` | Explicit match conditions |
| MS SQL Server | `MERGE INTO ...` | Explicit match conditions |
| SQLite | `INSERT ... ON CONFLICT DO UPDATE` | Targets a specific unique constraint |
| H2 | `MERGE INTO ...` | Explicit match conditions |

See [Upserts](upserts.md) for usage examples.

Expand All @@ -132,23 +163,53 @@ PostgreSQL's JSONB and MySQL/MariaDB's JSON types are fully supported when using

Beyond SQL syntax differences, databases support different native data types. Dialects handle the mapping between Kotlin/Java types and database-specific types automatically, so you can use idiomatic types in your entities without worrying about the underlying storage format.

- **PostgreSQL:** JSONB, UUID, arrays, INET, CIDR
- **MySQL/MariaDB:** JSON, TINYINT for booleans, ENUM
- **Oracle:** NUMBER, CLOB, sequences for ID generation
- **MS SQL Server:** NVARCHAR, UNIQUEIDENTIFIER, IDENTITY
- **PostgreSQL:** JSONB, UUID, arrays, INET, CIDR
- **MySQL/MariaDB:** JSON, TINYINT for booleans, ENUM
- **SQLite:** Dynamic typing, AUTOINCREMENT, file-based storage
- **H2:** Native UUID, sequences, ARRAY types

## Without a Dialect

Storm works without a specific dialect package by generating standard SQL. This is the typical setup during development and testing when using H2 as an in-memory database. The core framework handles entity mapping, queries, joins, transactions, streaming, dirty checking, and caching using only standard SQL. However, some features require database-specific syntax and will be unavailable without a dialect:
Storm works without a specific dialect package by generating standard SQL. The core framework handles entity mapping, queries, joins, transactions, streaming, dirty checking, and caching using only standard SQL. However, some features require database-specific syntax and will be unavailable without a dialect:

- **Upsert operations** require database-specific syntax
- **Database-specific optimizations** such as native pagination strategies

All other features (entity mapping, queries, joins, transactions, streaming, dirty checking, and caching) work identically regardless of dialect.

## Testing with SQLite

SQLite is a lightweight option for testing. It stores data in a single file (or in memory) and requires no server process. Add the `storm-sqlite` dialect dependency to enable SQLite-specific features like upsert support.

<Tabs groupId="language">
<TabItem value="kotlin" label="Kotlin" default>

```kotlin
val dataSource = SQLiteDataSource().apply {
url = "jdbc:sqlite::memory:"
}
val orm = ORMTemplate.of(dataSource)
```

</TabItem>
<TabItem value="java" label="Java">

```java
var dataSource = new SQLiteDataSource();
dataSource.setUrl("jdbc:sqlite::memory:");
var orm = ORMTemplate.of(dataSource);
```

</TabItem>
</Tabs>

Note that SQLite does not support sequences, row-level locking, or `INFORMATION_SCHEMA`. Constraint discovery uses JDBC metadata, and locking relies on SQLite's file-level locking mechanism.

## Testing with H2

H2 is an in-memory Java SQL database that starts instantly and requires no external processes. Storm includes built-in support for H2, making it the default choice for unit tests. Because H2 runs in-process, tests start in milliseconds and do not require Docker, network access, or database installation.
H2 is an in-memory Java SQL database that starts instantly and requires no external processes, making it the default choice for unit tests. Because H2 runs in-process, tests start in milliseconds and do not require Docker, network access, or database installation.

<Tabs groupId="language">
<TabItem value="kotlin" label="Kotlin" default>
Expand All @@ -172,7 +233,7 @@ var orm = ORMTemplate.of(dataSource);
</TabItem>
</Tabs>

No additional dialect dependency is needed for H2. This makes it easy to write fast tests that run without Docker or external databases.
For basic testing without upsert support, H2 works without any dialect dependency. To enable upsert support and other H2-specific optimizations (native UUID handling, tuple comparisons), add the `storm-h2` dialect dependency.

## Integration Testing with Real Databases

Expand All @@ -187,10 +248,10 @@ mvn test -pl storm-postgresql
## Tips

1. **Always include the dialect** for production databases to unlock all features
2. **Use H2** for unit tests; no additional dialect needed, fast startup
2. **Use H2 or SQLite** for unit tests; add `storm-h2` or `storm-sqlite` for upsert support
3. **Dialect is runtime-only**; it doesn't affect your compile-time code or entity definitions
4. **One dialect per application**; Storm auto-detects the right dialect from your connection URL
5. **Test with both**: Use H2 for fast unit tests and the production dialect for integration tests
5. **Test with both**: Use H2/SQLite for fast unit tests and the production dialect for integration tests

---

Expand Down
53 changes: 46 additions & 7 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,71 @@ The framework is organized around three core abstractions:

These abstractions share a common principle: explicit behavior over implicit magic. Every query is visible in the source code. Every relationship is loaded when you ask for it. Every transaction boundary is declared, not inferred. This makes Storm applications straightforward to debug, profile, and reason about.

## How Storm Differs from JPA
## Choose Your Path

If you are coming from JPA/Hibernate, the biggest shift is moving from mutable, proxy-backed entities with a managed lifecycle to stateless, immutable values. Storm has no persistence context, no first-level cache, no `EntityManager`, and no automatic change detection. This eliminates entire categories of bugs (LazyInitializationException, detached entity errors, unexpected flush ordering) while making performance predictable. For a detailed comparison, see the [Migration from JPA](migration-from-jpa.md) guide and the [Storm vs Other Frameworks](comparison.md) feature comparison.
Storm supports two ways to get started. Pick the one that fits your workflow.

## Step-by-Step Setup
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

This guide is split into three steps. Follow them in order for the fastest path from zero to a working application.
<Tabs>
<TabItem value="ai" label="AI-Assisted" default>

## 1. Installation
### AI-Assisted Setup

If you use an AI coding tool (Claude Code, Cursor, GitHub Copilot, Windsurf, or Codex), Storm provides rules, skills, and an optional database-aware MCP server that give the AI deep knowledge of Storm's conventions. The AI can generate entities from your schema, write queries, and verify its own work against a real database.

**1. Install the Storm CLI and run it in your project:**

```bash
npx @storm-orm/cli init
```

The interactive setup configures your AI tool with Storm's rules and skills, and optionally connects it to your development database for schema-aware code generation.

**2. Ask your AI tool to set up Storm:**

Once `storm init` has configured your tool, you can ask it to add the right dependencies, create entities from your database tables, and write queries. The AI has access to Storm's full documentation and your database schema.

For example:
- "Add Storm to this project with Spring Boot and PostgreSQL"
- "Create entities for the users and orders tables"
- "Write a repository method that finds orders by status with pagination"

**3. Verify:**

Storm's AI workflow includes built-in verification. The AI can run `ORMTemplate.validateSchema()` to prove entities match the database and `SqlCapture` to inspect generated SQL, all in an isolated H2 test database before anything touches production.

See [AI-Assisted Development](ai.md) for the full setup guide, available skills, and MCP server configuration.

</TabItem>
<TabItem value="manual" label="Manual">

### Manual Setup

Follow these three steps in order for the fastest path from zero to a working application.

**1. Installation**

Set up your project with the right dependencies, build flags, and optional modules.

**[Go to Installation](installation.md)**

## 2. First Entity
**2. First Entity**

Define your first entity, create an ORM template, and perform insert, read, update, and delete operations.

**[Go to First Entity](first-entity.md)**

## 3. First Query
**3. First Query**

Write custom queries, build repositories, stream results, and use the type-safe metamodel.

**[Go to First Query](first-query.md)**

</TabItem>
</Tabs>

---

## What's Next
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ Storm is focused on being a great ORM and SQL template engine. It intentionally

Storm works with any JDBC-compatible database. Dialect packages provide optimized support for:

![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql&logoColor=white) ![MySQL](https://img.shields.io/badge/MySQL-4479A1?logo=mysql&logoColor=white) ![MariaDB](https://img.shields.io/badge/MariaDB-003545?logo=mariadb&logoColor=white) ![Oracle](https://img.shields.io/badge/Oracle-F80000?logo=oracle&logoColor=white) ![SQL Server](https://img.shields.io/badge/SQL_Server-CC2927?logo=microsoftsqlserver&logoColor=white) ![H2](https://img.shields.io/badge/H2-0000bb?logoColor=white)
![Oracle](https://img.shields.io/badge/Oracle-F80000?logo=oracle&logoColor=white) ![SQL Server](https://img.shields.io/badge/SQL_Server-CC2927?logo=microsoftsqlserver&logoColor=white) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?logo=postgresql&logoColor=white) ![MySQL](https://img.shields.io/badge/MySQL-4479A1?logo=mysql&logoColor=white) ![MariaDB](https://img.shields.io/badge/MariaDB-003545?logo=mariadb&logoColor=white) ![SQLite](https://img.shields.io/badge/SQLite-003B57?logo=sqlite&logoColor=white) ![H2](https://img.shields.io/badge/H2-0000bb?logoColor=white)

See [Database Dialects](dialects.md) for installation and configuration details.

Expand Down
8 changes: 5 additions & 3 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,13 @@ Storm works with any JDBC-compatible database out of the box. Dialect modules pr

| Module | Database |
|--------|----------|
| `storm-oracle` | Oracle |
| `storm-mssqlserver` | SQL Server |
| `storm-postgresql` | PostgreSQL |
| `storm-mysql` | MySQL |
| `storm-mariadb` | MariaDB |
| `storm-oracle` | Oracle |
| `storm-mssqlserver` | SQL Server |
| `storm-sqlite` | SQLite |
| `storm-h2` | H2 |

```kotlin
runtimeOnly("st.orm:storm-postgresql")
Expand Down Expand Up @@ -212,7 +214,7 @@ storm-foundation (base interfaces)
└── storm-kotlin / storm-java21 (your primary dependency)
├── storm-kotlin-spring / storm-spring (Spring Framework)
│ └── storm-kotlin-spring-boot-starter / storm-spring-boot-starter
├── dialect modules (postgresql, mysql, mariadb, oracle, mssqlserver)
├── dialect modules (postgresql, mysql, mariadb, oracle, mssqlserver, sqlite, h2)
└── JSON modules (jackson2, jackson3, kotlinx-serialization)
```

Expand Down
Loading
Loading