Skip to content

Commit e2ad35d

Browse files
authored
Improve API and AI. (#115) (#116)
1 parent 8447ed2 commit e2ad35d

161 files changed

Lines changed: 3347 additions & 3502 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/docs.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ jobs:
6565
done
6666
6767
- name: Generate llms-full.txt
68-
run: bash website/scripts/generate-llms-full.sh
68+
run: bash scripts/generate-llms-full.sh
69+
working-directory: website
6970

7071
- name: Build Docusaurus
7172
run: npm run build

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ build/
4242
.DS_Store
4343

4444
### Maven Flatten Plugin ###
45-
.flattened-pom.xml
45+
**/.flattened-pom.xml
4646

4747
### Docusaurus ###
4848
website/node_modules/

README.md

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
**Storm** is a modern, high-performance ORM for Kotlin 2.0+ and Java 21+, built around a powerful SQL template engine. It focuses on simplicity, type safety, and predictable performance through immutable models and compile-time metadata.
1212

13-
**Key benefits:**
13+
**Core ORM benefits:**
1414

1515
- **Minimal code**: Define entities with simple records/data classes and query with concise, readable syntax; no boilerplate.
1616
- **Parameterized by default**: String interpolations are automatically converted to bind variables, making queries SQL injection safe by design.
@@ -21,6 +21,17 @@
2121
- **Performance**: Template caching, transaction-scoped entity caching, and zero-overhead dirty checking (thanks to immutability) ensure efficient database interactions. Batch processing, lazy streams, and upserts are built in.
2222
- **Universal Database Compatibility**: Fully compatible with all SQL databases, it offers flexibility and broad applicability across various database systems.
2323

24+
Storm also includes an AI-assisted workflow for database development. It gives AI tools full schema awareness through a local MCP server, guides them with Storm-specific skills, and closes the loop with automated tests. The AI generates code, but the final checks are done by running code against the schema and captured SQL, not by trusting LLM reasoning.
25+
26+
To set up the AI workflow in your project:
27+
28+
```bash
29+
npm install -g @storm-orm/cli
30+
storm init
31+
```
32+
33+
This installs Storm's rules, skills, and optional local MCP setup for supported AI coding tools. See [AI-Assisted Development](docs/ai.md) for the full workflow.
34+
2435
## Why Storm?
2536

2637
Storm draws inspiration from established ORMs such as Hibernate, but is built from scratch around a clear design philosophy: capturing exactly what you want to do using the minimum amount of code, optimized for Kotlin and modern Java.
@@ -42,6 +53,25 @@ Storm embraces SQL rather than abstracting it away. It simplifies database inter
4253

4354
**Storm is ideal for** developers who understand that the best solutions emerge when object model and database model work in harmony. If you value a database-first approach where records naturally mirror your schema, Storm is built for you. Custom mappings are supported when needed, but the real elegance comes from alignment, not abstraction.
4455

56+
## AI Workflow
57+
58+
AI tools can write a lot of database code quickly, but subtle mistakes are still common: wrong joins, missing constraints, stale schema assumptions, or queries that compile but do the wrong thing.
59+
60+
Storm addresses that in two ways.
61+
62+
First, it improves generation quality. A local MCP server gives the AI full schema awareness without exposing credentials or data, and Storm skills teach the AI how to create entities, queries, repositories, and migrations that follow Storm's conventions.
63+
64+
Second, it verifies the result with automated tests. Storm can validate that generated entities still match the schema and that generated queries behave as intended. These checks run in unit tests, so the final gate is actual code execution rather than model self-evaluation.
65+
66+
The workflow is simple:
67+
68+
1. You prompt the AI.
69+
2. The AI uses Storm skills and local schema context to generate code.
70+
3. Storm verifies the generated entities and queries in tests.
71+
4. You review the result and keep moving with more confidence.
72+
73+
This is the core idea: AI generates database code, and Storm closes the loop with context and verification.
74+
4575
## Choose Your Language
4676

4777
Both Kotlin and Java support SQL Templates for powerful query composition. Kotlin additionally provides a type-safe DSL with infix operators for a more idiomatic experience.
@@ -143,7 +173,7 @@ Storm provides a Bill of Materials (BOM) for centralized version management. Imp
143173
<dependency>
144174
<groupId>st.orm</groupId>
145175
<artifactId>storm-bom</artifactId>
146-
<version>1.11.0</version>
176+
<version>@@STORM_VERSION@@</version>
147177
<type>pom</type>
148178
<scope>import</scope>
149179
</dependency>
@@ -155,7 +185,7 @@ Storm provides a Bill of Materials (BOM) for centralized version management. Imp
155185

156186
```kotlin
157187
dependencies {
158-
implementation(platform("st.orm:storm-bom:1.11.0"))
188+
implementation(platform("st.orm:storm-bom:@@STORM_VERSION@@"))
159189
}
160190
```
161191

@@ -165,7 +195,7 @@ With the BOM imported, add Storm modules without specifying versions:
165195

166196
```kotlin
167197
dependencies {
168-
implementation(platform("st.orm:storm-bom:1.11.0"))
198+
implementation(platform("st.orm:storm-bom:@@STORM_VERSION@@"))
169199
implementation("st.orm:storm-kotlin")
170200
runtimeOnly("st.orm:storm-core")
171201
// Use storm-compiler-plugin-2.0 for Kotlin 2.0.x, -2.1 for 2.1.x, etc.

docs/api-java.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The main Java API module. It provides the `ORMTemplate` entry point, repository
1616
<dependency>
1717
<groupId>st.orm</groupId>
1818
<artifactId>storm-java21</artifactId>
19-
<version>1.11.0</version>
19+
<version>@@STORM_VERSION@@</version>
2020
</dependency>
2121
```
2222

@@ -44,7 +44,7 @@ Spring Framework integration for Java. Provides `RepositoryBeanFactoryPostProces
4444
<dependency>
4545
<groupId>st.orm</groupId>
4646
<artifactId>storm-spring</artifactId>
47-
<version>1.11.0</version>
47+
<version>@@STORM_VERSION@@</version>
4848
</dependency>
4949
```
5050

@@ -58,7 +58,7 @@ Spring Boot auto-configuration for Java. Automatically creates an `ORMTemplate`
5858
<dependency>
5959
<groupId>st.orm</groupId>
6060
<artifactId>storm-spring-boot-starter</artifactId>
61-
<version>1.11.0</version>
61+
<version>@@STORM_VERSION@@</version>
6262
</dependency>
6363
```
6464

@@ -83,7 +83,7 @@ The `storm-metamodel-processor` annotation processor generates type-safe metamod
8383
<dependency>
8484
<groupId>st.orm</groupId>
8585
<artifactId>storm-metamodel-processor</artifactId>
86-
<version>1.11.0</version>
86+
<version>@@STORM_VERSION@@</version>
8787
<scope>provided</scope>
8888
</dependency>
8989
```

docs/api-kotlin.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ The main Kotlin API module. It provides the `ORMTemplate` interface, extension f
1414

1515
```kotlin
1616
// Gradle (Kotlin DSL)
17-
implementation("st.orm:storm-kotlin:1.11.0")
17+
implementation("st.orm:storm-kotlin:@@STORM_VERSION@@")
1818
```
1919

2020
```xml
2121
<!-- Maven -->
2222
<dependency>
2323
<groupId>st.orm</groupId>
2424
<artifactId>storm-kotlin</artifactId>
25-
<version>1.11.0</version>
25+
<version>@@STORM_VERSION@@</version>
2626
</dependency>
2727
```
2828

@@ -33,7 +33,7 @@ The Kotlin API does not depend on any preview features. All APIs are stable and
3333
Spring Framework integration for Kotlin. Provides `RepositoryBeanFactoryPostProcessor` for repository auto-discovery and injection, `@EnableTransactionIntegration` for bridging Storm's programmatic transactions with Spring's `@Transactional`, and transaction-aware coroutine support. Add this module when you use Spring Framework without Spring Boot.
3434

3535
```kotlin
36-
implementation("st.orm:storm-kotlin-spring:1.11.0")
36+
implementation("st.orm:storm-kotlin-spring:@@STORM_VERSION@@")
3737
```
3838

3939
See [Spring Integration](spring-integration.md) for configuration details.
@@ -43,7 +43,7 @@ See [Spring Integration](spring-integration.md) for configuration details.
4343
Spring Boot auto-configuration for Kotlin. Automatically creates an `ORMTemplate` bean from the `DataSource`, discovers repositories, enables transaction integration, and binds `storm.*` properties from `application.yml`. This is the recommended dependency for Spring Boot applications.
4444

4545
```kotlin
46-
implementation("st.orm:storm-kotlin-spring-boot-starter:1.11.0")
46+
implementation("st.orm:storm-kotlin-spring-boot-starter:@@STORM_VERSION@@")
4747
```
4848

4949
See [Spring Integration: Spring Boot Starter](spring-integration.md#spring-boot-starter) for what the starter provides and how to override its defaults.
@@ -96,7 +96,7 @@ plugins {
9696
}
9797

9898
dependencies {
99-
ksp("st.orm:storm-metamodel-ksp:1.11.0")
99+
ksp("st.orm:storm-metamodel-ksp:@@STORM_VERSION@@")
100100
}
101101
```
102102

@@ -115,7 +115,7 @@ dependencies {
115115
<path>
116116
<groupId>st.orm</groupId>
117117
<artifactId>storm-metamodel-processor</artifactId>
118-
<version>1.11.0</version>
118+
<version>@@STORM_VERSION@@</version>
119119
</path>
120120
</annotationProcessorPaths>
121121
</configuration>

docs/batch-streaming.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Database performance often degrades when applications issue many individual SQL
1212

1313
## Batch Processing
1414

15-
When you pass a list of entities to Storm's insert, update, delete, or upsert methods, Storm automatically uses JDBC batch statements. The framework groups rows together and sends them to the database in a single round-trip, rather than issuing one statement per entity.
15+
When you pass a list of entities to Storm's insert, update, remove, or upsert methods, Storm automatically uses JDBC batch statements. The framework groups rows together and sends them to the database in a single round-trip, rather than issuing one statement per entity.
1616

1717
### Batch Insert
1818

@@ -73,25 +73,25 @@ orm.entity(User.class).update(updatedUsers);
7373
</TabItem>
7474
</Tabs>
7575

76-
### Batch Delete
76+
### Batch Remove
7777

78-
Batch deletes remove multiple entities in a single round-trip. Storm generates a batched DELETE using each entity's primary key.
78+
Batch removes delete multiple entities in a single round-trip. Storm generates a batched DELETE using each entity's primary key.
7979

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

8383
```kotlin
84-
orm delete users
84+
orm remove users
8585

86-
// Or delete all entities of a type
87-
orm.deleteAll<User>()
86+
// Or remove all entities of a type
87+
orm.removeAll<User>()
8888
```
8989

9090
</TabItem>
9191
<TabItem value="java" label="Java">
9292

9393
```java
94-
orm.entity(User.class).delete(users);
94+
orm.entity(User.class).remove(users);
9595
```
9696

9797
</TabItem>

docs/common-patterns.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -454,13 +454,13 @@ Use the `scroll()` method on any entity repository with a `Scrollable` that capt
454454
// First page of 20 users ordered by ID
455455
val window: Window<User> = userRepository.scroll(Scrollable.of(User_.id, 20))
456456

457-
// Navigate forward: nextScrollable() is non-null whenever the window has content.
457+
// Navigate forward: next() is non-null whenever the window has content.
458458
// hasNext() is an informational flag indicating whether more rows existed at
459459
// query time, but the developer decides whether to follow the cursor.
460-
val next: Window<User> = userRepository.scroll(window.nextScrollable())
460+
val next: Window<User> = userRepository.scroll(window.next())
461461

462462
// Navigate backward
463-
val previous: Window<User> = userRepository.scroll(window.previousScrollable())
463+
val previous: Window<User> = userRepository.scroll(window.previous())
464464
```
465465

466466
</TabItem>
@@ -470,19 +470,19 @@ val previous: Window<User> = userRepository.scroll(window.previousScrollable())
470470
// First page of 20 users ordered by ID
471471
Window<User> window = userRepository.scroll(Scrollable.of(User_.id, 20));
472472

473-
// Navigate forward: nextScrollable() is non-null whenever the window has content.
473+
// Navigate forward: next() is non-null whenever the window has content.
474474
// hasNext() is an informational flag indicating whether more rows existed at
475475
// query time, but the developer decides whether to follow the cursor.
476-
Window<User> next = userRepository.scroll(window.nextScrollable());
476+
Window<User> next = userRepository.scroll(window.next());
477477

478478
// Navigate backward
479-
Window<User> previous = userRepository.scroll(window.previousScrollable());
479+
Window<User> previous = userRepository.scroll(window.previous());
480480
```
481481

482482
</TabItem>
483483
</Tabs>
484484

485-
Each method returns a `Window` containing the page content and navigation cursors for sequential traversal. The `hasNext()` and `hasPrevious()` flags reflect whether additional rows existed at query time, but they are not prerequisites for calling `nextScrollable()` or `previousScrollable()`. Both methods return a non-null `Scrollable` whenever the window contains at least one element, and return `null` only when the window is empty. This means you can always follow the cursor if you choose to; for example, new rows may have been inserted after the original query. For REST APIs, `Window` also provides `nextCursor()` and `previousCursor()` to serialize the scroll position as an opaque string, and `Scrollable.fromCursor(key, cursor)` to reconstruct a `Scrollable` from a cursor string. See [Repositories: Scrolling](repositories.md#scrolling) for the full API, including sort overloads, filtering, and Ref variants.
485+
Each method returns a `Window` containing the page content and navigation cursors for sequential traversal. The `hasNext()` and `hasPrevious()` flags reflect whether additional rows existed at query time, but they are not prerequisites for calling `next()` or `previous()`. Both methods return a non-null `Scrollable` whenever the window contains at least one element, and return `null` only when the window is empty. This means you can always follow the cursor if you choose to; for example, new rows may have been inserted after the original query. For REST APIs, `Window` also provides `nextCursor()` and `previousCursor()` to serialize the scroll position as an opaque string, and `Scrollable.fromCursor(key, cursor)` to reconstruct a `Scrollable` from a cursor string. See [Repositories: Scrolling](repositories.md#scrolling) for the full API, including sort overloads, filtering, and Ref variants.
486486

487487
### Choosing Between the Two
488488

@@ -496,8 +496,8 @@ Each method returns a `Window` containing the page content and navigation cursor
496496
| Performance at page 1 | Good | Good |
497497
| Performance at page 1,000 | Degrades (database must skip rows) | Consistent (index seek) |
498498
| Handles concurrent inserts | Rows may shift between pages | Stable cursor |
499-
| Navigate forward | `page.nextPageable()` | `window.nextScrollable()` |
500-
| Navigate backward | `page.previousPageable()` | `window.previousScrollable()` |
499+
| Navigate forward | `page.nextPageable()` | `window.next()` |
500+
| Navigate backward | `page.previousPageable()` | `window.previous()` |
501501

502502
Use pagination when you need random page access or a total count (for example, displaying "Page 3 of 12" in a UI). Use scrolling when you need consistent performance over deep result sets or when the data changes frequently between requests.
503503

docs/cursors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ The following Java types can be used as cursor values (key or sort fields) out o
8585

8686
If your key or sort field uses a type not in this list, serialization via `toCursor()` will throw an `IllegalStateException`. You can either use one of the supported types for your key/sort columns, or register a custom codec.
8787

88-
Note that in-memory navigation (using `nextScrollable()` and `previousScrollable()` directly, without serializing to a cursor string) works with any type, including inline records and other composite types. The type restriction only applies to `toCursor()` serialization.
88+
Note that in-memory navigation (using `next()` and `previous()` directly, without serializing to a cursor string) works with any type, including inline records and other composite types. The type restriction only applies to `toCursor()` serialization.
8989

9090
## Custom cursor codecs
9191

0 commit comments

Comments
 (0)