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
4 changes: 3 additions & 1 deletion docs/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ The following tables provide a side-by-side comparison of concrete features acro
|---------|-------|-----|-------------|---------|------|------|--------|---------|-------|
| Lines per entity | ~5 | ~30<sup>1</sup> | ~30<sup>1</sup> | ~20+ | Generated | ~15 | ~10 | ~12 | ~15 |
| Immutable entities | Yes | No | No | Yes | Yes | Yes | Yes | DSL only | No |
| Session state | None | Persistence context | Via JPA | None | None | None | None | DAO only | Entity tracking |
| Polymorphism | Yes<sup>2</sup> | Yes | Via JPA | No | No | No | No<sup>8</sup> | No | No |
| Automatic relationships | Yes | Yes<sup>3</sup> | Via JPA | No | No | No | Yes | DAO only | No |
| Cascade persist | No | Yes | Yes | No | No | No | Yes | No | No |
Expand All @@ -33,8 +34,9 @@ The following tables provide a side-by-side comparison of concrete features acro
| Feature | Storm | JPA | Spring Data | MyBatis | jOOQ | JDBI | Jimmer | Exposed | Ktorm |
|---------|-------|-----|-------------|---------|------|------|--------|---------|-------|
| Type-safe queries | Yes | Criteria | No | No | Yes | No | Yes | Yes | Yes |
| SQL Templates | Yes | No | No | XML/Ann | Yes | Yes | Native<sup>9</sup> | No | No |
| SQL / SQL templates | Yes | Native queries | Via JPA | XML/Ann | Yes | Yes | Native<sup>9</sup> | exec() | Raw JDBC |
| N+1 prevention | Yes | No | No | No | Manual | Manual | Yes | No | No |
| Query across relations | One line | JPQL/Criteria | Derived/JPQL | Manual SQL | Path joins | Manual SQL | Implicit joins | Manual joins | Manual joins |
| Lazy loading | Refs | Yes | Yes | No | No | No | Fetchers | Yes | Yes |
| Scrolling | Yes | No | Yes | No | Yes | No | No | No | No |
| JSON columns | Yes | Yes<sup>4</sup> | Via JPA | Manual | Yes | Module | Yes | Yes | Module |
Expand Down
190 changes: 159 additions & 31 deletions website/src/components/tutorial/tutorialTheme.js

Large diffs are not rendered by default.

31 changes: 19 additions & 12 deletions website/src/pages/comparison.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import {TUT_CSS, navHtml, FOOT_HTML, wireSqlToggles} from '../components/tutoria
// The comparison page at /comparison, in the landing/tutorial style. A
// scannable, code-light companion to the in-depth docs/comparison.md: a
// decision matrix plus a compact card per framework, each linking to the full
// docs pairing. Jimmer is treated exactly like the other frameworks (a matrix
// column and a card), with its detailed pairing living in the docs alongside
// the rest. Kept fair per the project's competitor-copy rule: only differences
// that are real and that the rival does not already cover are called out.
// docs pairing. Jimmer has a card but no matrix column: the matrix stays at
// the mainstream decision set for readability, while the card and its docs
// pairing cover the closest peer in the place that can express the real
// difference (conciseness). Kept fair per the project's competitor-copy rule:
// only differences that are real and that the rival does not already cover
// are called out.

const TITLE = 'Comparison · Storm vs JPA, jOOQ, Exposed, Jimmer';
const DESC =
Expand Down Expand Up @@ -66,16 +68,21 @@ function buildBody() {
const matrix = `
<table class="cmp">
<thead><tr>
<th>Feature</th><th>Storm</th><th>JPA / Hibernate</th><th>jOOQ</th><th>Jimmer</th><th>Exposed</th><th>Ktorm</th>
<th>Feature</th><th>Storm</th><th>JPA / Hibernate</th><th>jOOQ</th><th>Exposed</th><th>Ktorm</th>
</tr></thead>
<tbody>
<tr><td>Entity model</td><td>Immutable data class (~5 lines)</td><td>Mutable class (~30, ~10 with Lombok)</td><td>Generated from schema</td><td>Immutable interface (KSP-generated)</td><td>DSL table object (+ optional DAO)</td><td>Mutable interface (+ DSL table)</td></tr>
<tr><td>Immutable entities</td><td>Yes</td><td>No</td><td>Yes</td><td>Yes</td><td>DSL only</td><td>No</td></tr>
<tr><td>Type-safe queries</td><td>Yes</td><td>Criteria API</td><td>Yes</td><td>Yes</td><td>Yes</td><td>Yes</td></tr>
<tr><td>N+1 handling</td><td>Single-query entity graph</td><td>Common pitfall</td><td>Manual</td><td>Batched queries</td><td>Manual</td><td>Manual</td></tr>
<tr><td>Full SQL escape hatch</td><td>SQL templates</td><td>Native queries</td><td>It is SQL</td><td>SQL expressions</td><td>Raw exec()</td><td>Raw JDBC</td></tr>
<tr><td>Languages</td><td>Kotlin + Java</td><td>Kotlin + Java</td><td>Kotlin + Java</td><td>Kotlin + Java</td><td>Kotlin only</td><td>Kotlin only</td></tr>
<tr><td>License</td><td>Apache 2.0</td><td>LGPL 2.1</td><td>Commercial for some DBs</td><td>Apache 2.0</td><td>Apache 2.0</td><td>Apache 2.0</td></tr>
<tr><td>Entity model</td><td>Immutable data class (~5 lines)</td><td>Mutable class (~30, ~10 with Lombok)</td><td>Generated from schema</td><td>DSL table object (+ optional DAO)</td><td>Mutable interface (+ DSL table)</td></tr>
<tr><td>Immutable entities</td><td>Yes</td><td>No</td><td>Yes</td><td>DSL only</td><td>No</td></tr>
<tr><td>Type-safe queries</td><td>Yes</td><td>Criteria API</td><td>Yes</td><td>Yes</td><td>Yes</td></tr>
<tr><td>N+1 handling</td><td>Single-query entity graph</td><td>Common pitfall</td><td>Manual</td><td>Manual</td><td>Manual</td></tr>
<tr><td>Query across relations</td><td>One line: joins and mapping derived from @FK</td><td>JPQL strings or Criteria builders</td><td>Implicit path joins + multiset</td><td>Manual joins and row mapping</td><td>Manual joins</td></tr>
<tr><td>Session state</td><td>None: no session, no flush</td><td>Persistence context, flush, dirty checking</td><td>None</td><td>DSL none · DAO transaction-bound</td><td>Per-entity change tracking</td></tr>
<tr><td>Deferred loading</td><td>Explicit Ref&lt;T&gt;</td><td>Proxies, session-bound</td><td>Not applicable</td><td>DAO lazy, transaction-bound</td><td>Manual joins</td></tr>
<tr><td>Standalone transactions</td><td>Propagation, isolation, timeout, commit hooks</td><td>EntityTransaction · JTA/Spring for more</td><td>Lambda API, nested</td><td>Nested, isolation config</td><td>Lambda API</td></tr>
<tr><td>Row mapping</td><td>Compile-time generated, reflection-free</td><td>Reflection / bytecode</td><td>Generated records</td><td>Manual (DSL)</td><td>Dynamic proxies</td></tr>
<tr><td>Full SQL escape hatch</td><td>SQL / SQL templates</td><td>Native queries</td><td>It is SQL</td><td>Raw exec()</td><td>Raw JDBC</td></tr>
<tr><td>Languages</td><td>Kotlin + Java</td><td>Kotlin + Java</td><td>Kotlin + Java</td><td>Kotlin only</td><td>Kotlin only</td></tr>
<tr><td>License</td><td>Apache 2.0</td><td>LGPL 2.1</td><td>Commercial for some DBs</td><td>Apache 2.0</td><td>Apache 2.0</td></tr>
</tbody>
</table>`;

Expand Down
46 changes: 32 additions & 14 deletions website/src/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ const CSS = `
.storm-home .btn:hover{border-color:#34343d;transform:translateY(-1px)}
.storm-home .btn.primary{background:var(--accent);color:#0a0a0f;border-color:var(--accent);font-weight:600}
.storm-home .btn.primary:hover{background:#9aa3ff}
/* The hero conversion button is filled with the brand gradient (the same one
.grad clips into the hero text), so it pops by brightness while staying
perfectly on-palette. Border off: it can't take a gradient and the fill
supplies the edge. */
.storm-home .btn.primary.go{background:linear-gradient(100deg,#a78bfa,#818cf8 50%,#7dd3fc);border-color:transparent}
.storm-home .btn.primary.go:hover{filter:brightness(1.12)}

/* hero — left aligned */
.storm-home header{padding:46px 0 34px}
Expand Down Expand Up @@ -81,15 +87,24 @@ const CSS = `
@media(prefers-reduced-motion:reduce){.storm-home .hero-rot>span,.storm-home .hero-swap>span{transition:none}}
/* On small screens the h1 min (42px) is too large for the longer principles to
stay on one line, so scale the rotating line down a little below the hero. */
@media(max-width:600px){.storm-home .hero-rot>span{font-size:clamp(20px,6vw,30px)}}
@media(max-width:600px){
.storm-home .hero-rot>span{font-size:clamp(20px,6vw,30px)}
/* Tighten the fold: campaign traffic is ~100% mobile and the hero CTA must
be tappable without scrolling, so shrink the header spacing and sub copy
and stack the buttons full-width. */
.storm-home header{padding:30px 0 26px}
.storm-home .sub{font-size:15.5px;margin-top:18px}
.storm-home .hero-cta{margin-top:20px}
.storm-home .hero-cta .btn{flex:1 1 100%;justify-content:center;height:44px}
.storm-home .stage{margin-top:34px}
}
.storm-home .sub{max-width:600px;margin:24px 0 0;color:var(--muted);font-size:18px;line-height:1.62}
.storm-home .sub a{color:var(--accent);text-decoration:underline;text-underline-offset:3px}
.storm-home .sub a:hover{color:#9aa3ff}
/* "Your move." keeps the hero gradient (transparent color, so the generic
.sub a accent must not win) and only reveals its underline on hover. */
.storm-home .sub a.hero-move{font-weight:600;color:transparent;text-decoration:none}
.storm-home .sub a.hero-move:hover{text-decoration:underline;text-decoration-color:#a5b4fc;text-decoration-thickness:2px;text-underline-offset:4px}
.storm-home .cta{display:flex;gap:14px;margin-top:32px;flex-wrap:wrap}
/* Hero CTA: the primary conversion action, kept high so it sits above the
fold on phones. */
.storm-home .hero-cta{margin-top:26px}

/* editor */
.storm-home .stage{margin:54px 0 0;max-width:880px}
Expand Down Expand Up @@ -214,7 +229,7 @@ const BODY = `
<a href="/comparison">Comparison</a>
<a href="/blog/">Blog</a>
<a href="/docs/">Docs</a>
<a class="gh" href="https://github.com/orgs/storm-orm/repositories">GitHub</a>
<a class="gh" href="https://github.com/orgs/storm-orm/repositories" target="_blank" rel="noopener">GitHub</a>
<a href="/quickstart" class="btn primary" style="height:36px">Get started</a>
</div>
</div></nav>
Expand All @@ -228,14 +243,17 @@ const BODY = `
<span class="grad"><a href="/quickstart">Try it.</a></span>
<span class="grad"><a href="/quickstart">Break it.</a></span>
<span class="grad"><a href="/comparison">Challenge it.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework">Love it.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework/discussions">Hate it.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework/discussions">Tell us.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework">Follow us.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework/discussions">Join us.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework" target="_blank" rel="noopener">Love it.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework/discussions" target="_blank" rel="noopener">Hate it.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework/discussions" target="_blank" rel="noopener">Tell us.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework" target="_blank" rel="noopener">Follow us.</a></span>
<span class="grad"><a href="https://github.com/storm-orm/storm-framework/discussions" target="_blank" rel="noopener">Join us.</a></span>
</span></h1>
<p class="sub" style="max-width:940px">How would you design an ORM you would enjoy using? Immutable data-class entities? One-line queries, checked at compile time? No proxies, no N+1, no persistence context? That is ST/ORM.</p>
<p class="sub" style="max-width:940px;margin-top:12px">After 18 months of commercial use, it is ready to be challenged. <a href="/quickstart" class="grad hero-move">Your move.</a></p>
<div class="cta hero-cta">
<a href="/quickstart" class="btn primary go">Try it in 5 minutes →</a>
<a href="/comparison" class="btn">Compare with your ORM</a>
</div>

<div class="stage">
<div class="editor">
Expand Down Expand Up @@ -304,13 +322,13 @@ const BODY = `
<div class="cta" style="justify-content:center;margin-top:56px">
<a href="/quickstart" class="btn primary">Get started →</a>
<a href="/examples/" class="btn">Example apps</a>
<a href="https://github.com/storm-orm/storm-framework" class="btn">Star on GitHub</a>
<a href="https://github.com/storm-orm/storm-framework" target="_blank" rel="noopener" class="btn">Star on GitHub</a>
</div>
</div></section>

<footer><div class="wrap foot">
<div class="brand"><img class="logo" src="/img/storm-light.png" alt="Storm" /></div>
<div class="links"><a href="/">orm.st</a><a href="/tutorials/">Tutorials</a><a href="/examples/">Examples</a><a href="/comparison">Comparison</a><a href="/blog/">Blog</a><a href="https://github.com/storm-orm/storm-framework">GitHub</a><a href="https://central.sonatype.com/namespace/st.orm">Maven Central</a></div>
<div class="links"><a href="/">orm.st</a><a href="/tutorials/">Tutorials</a><a href="/examples/">Examples</a><a href="/comparison">Comparison</a><a href="/blog/">Blog</a><a href="https://github.com/storm-orm/storm-framework" target="_blank" rel="noopener">GitHub</a><a href="https://central.sonatype.com/namespace/st.orm">Maven Central</a></div>
</div></footer>
`;

Expand Down
Loading
Loading