<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Foundations JDBC Blog</title>
        <link>https://foundations.typr.dev/blog</link>
        <description>Foundations JDBC Blog</description>
        <lastBuildDate>Sun, 05 Apr 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Introducing Foundations JDBC: Type-Safe Database Access for the JVM]]></title>
            <link>https://foundations.typr.dev/blog/introducing-foundations-jdbc</link>
            <guid>https://foundations.typr.dev/blog/introducing-foundations-jdbc</guid>
            <pubDate>Sun, 05 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Every type your database has, as a real typed value. Queries that compose. No annotations, no reflection, no surprises.]]></description>
            <content:encoded><![CDATA[<p>What if your JDBC library actually knew what your database types were?</p>
<p>Not <code>Object</code>. Not <code>getInt()</code> with a column index and a prayer. Real types — <code>int4range</code>, <code>jsonb</code>, <code>STRUCT</code>, <code>LIST&lt;MAP&lt;VARCHAR, INTEGER&gt;&gt;</code>, <code>GEOGRAPHY</code> — modeled exactly as the database defines them, with full roundtrip fidelity.</p>
<p>That's what we built. <strong>Foundations JDBC</strong> is an open-source, MIT-licensed JDBC library for Java, Kotlin, and Scala. It gives you composable SQL fragments, typed row codecs, and test-time query verification — across PostgreSQL, MariaDB, DuckDB, Oracle, SQL Server, and DB2.</p>
<p>Today we're releasing <strong>1.0.0-RC3</strong>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-problem">The Problem<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#the-problem" class="hash-link" aria-label="Direct link to The Problem" title="Direct link to The Problem" translate="no">​</a></h2>
<p>Every JVM developer who writes SQL has hit the same walls.</p>
<p><strong>Queries are unchecked strings.</strong> Rename a column in your schema and nothing fails until production. No existing library catches this at test time.</p>
<p><strong>Nullability is invisible.</strong> A nullable column and a non-nullable column have the same Java type. You find out which is which when <code>NullPointerException</code> fires at 2 AM.</p>
<p><strong>Type fidelity is lost.</strong> Your DuckDB <code>STRUCT</code> becomes a shapeless <code>Object</code>. Your PostgreSQL <code>int4range</code> becomes a string you have to parse yourself. The database has real types — your library just ignores them.</p>
<p><strong>Database-specific features are second-class.</strong> PostgreSQL arrays, Oracle <code>MULTISET</code>, DuckDB <code>STRUCT</code>, MariaDB unsigned types — every interesting database feature requires escape hatches and manual JDBC gymnastics.</p>
<p>Foundations JDBC solves all four.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="query-analysis-find-sql-bugs-at-test-time-not-2-am">Query Analysis: Find SQL Bugs at Test Time, Not 2 AM<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#query-analysis-find-sql-bugs-at-test-time-not-2-am" class="hash-link" aria-label="Direct link to Query Analysis: Find SQL Bugs at Test Time, Not 2 AM" title="Direct link to Query Analysis: Find SQL Bugs at Test Time, Not 2 AM" translate="no">​</a></h2>
<p>This is the feature no other Java SQL library has, and the reason we built the rest.</p>
<p><a class="" href="https://foundations.typr.dev/docs/query-analysis">Query Analysis</a> prepares your SQL against a real database and verifies that parameter types, column types, nullability, and column counts all match your code. A single test verifies every query in your codebase:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token annotation punctuation" style="color:#393A34">@Test</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">void</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">verifyAllQueries</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">var</span><span class="token plain"> analyzables </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">AnalyzableScanner</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">scan</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"com.myapp.repository"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">QueryChecker</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">create</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">transactor</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">checkAll</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">analyzables</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><code>AnalyzableScanner</code> discovers every <a class="" href="https://foundations.typr.dev/docs/operations"><code>Operation</code></a>, <a class="" href="https://foundations.typr.dev/docs/templates"><code>Template</code></a>, and <code>RowTemplate</code> in the given package. Add a new query anywhere — it's automatically included next test run. No manual list maintenance.</p>
<p>When something fails, the report tells you exactly what went wrong:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">✗ 2 error(s) found:</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  1. Column 3 'created_at': type mismatch</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     │ Declared: int4 (JDBC: INTEGER)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     │ Returned: timestamptz (JDBC: TIMESTAMP_WITH_TIMEZONE)</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     └ The declared type cannot read from TIMESTAMP_WITH_TIMEZONE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  2. Column 4 'email': nullability mismatch</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     │ The database says this column is nullable</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     │ But the type text is not Optional</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">     └ Use .opt() to make the type nullable</span><br></span></code></pre></div></div>
<p>jOOQ validates its DSL at compile time but can't check hand-written SQL. Hibernate validates annotations at startup but not query correctness. Foundations JDBC validates your actual queries against your actual database.</p>
<p><a class="" href="https://foundations.typr.dev/docs/templates">Templates</a> with <code>.optionally()</code> produce 2^N possible query shapes from N optional predicates — Query Analysis verifies every combination automatically. <a class="" href="https://foundations.typr.dev/docs/composing-operations">Composed operations</a> are walked recursively, verifying every SQL statement in the tree. <a class="" href="https://foundations.typr.dev/docs/stored-procedures">Stored procedures</a> are checked too — parameter counts, types, and modes all verified against the database catalog.</p>
<p>This is what makes the rest of the library worth building. Every feature below feeds into Query Analysis.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-quick-look">A Quick Look<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#a-quick-look" class="hash-link" aria-label="Direct link to A Quick Look" title="Direct link to A Quick Look" translate="no">​</a></h2>
<p>Here's the shortest path from zero to a running query. DuckDB runs in-memory — no database server needed:</p>
<div class="language-kotlin codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-kotlin codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> dev</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">typr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">foundationskt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">import</span><span class="token plain"> dev</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">typr</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">foundationskt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:#393A34">.</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fun</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">val</span><span class="token plain"> tx </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> ConnectionSource</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">of</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        DuckDbConfig</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">inMemory</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">build</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">transactor</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">val</span><span class="token plain"> answer</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Int </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> sql </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token string-literal singleline string" style="color:#e3116c">"SELECT 42"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">queryExactlyOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">DuckDbTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">integer</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">transact</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">println</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-literal singleline string" style="color:#e3116c">"Result: </span><span class="token string-literal singleline interpolation interpolation-punctuation punctuation" style="color:#393A34">$</span><span class="token string-literal singleline interpolation expression">answer</span><span class="token string-literal singleline string" style="color:#e3116c">"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// Result: 42</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p><code>sql { }</code> is Kotlin's <a class="" href="https://foundations.typr.dev/docs/kotlin-interpolation">type-safe string interpolation</a> for SQL. <code>DuckDbTypes.integer</code> tells the library exactly how to read the value. <a class="" href="https://foundations.typr.dev/docs/transactors"><code>transact(tx)</code></a> obtains a connection, runs in a transaction, commits on success, rolls back on error, and cleans up. The return type is <code>Int</code>, not <code>Object</code>, not <code>ResultSet</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="row-codecs-define-once-use-everywhere">Row Codecs: Define Once, Use Everywhere<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#row-codecs-define-once-use-everywhere" class="hash-link" aria-label="Direct link to Row Codecs: Define Once, Use Everywhere" title="Direct link to Row Codecs: Define Once, Use Everywhere" translate="no">​</a></h2>
<p>A <a class="" href="https://foundations.typr.dev/docs/row-codecs"><code>RowCodec</code></a> maps database columns to your domain objects. Define it once — it works for reading queries, writing inserts, <a class="" href="https://foundations.typr.dev/docs/streaming-inserts">streaming with COPY</a>, <a class="" href="https://foundations.typr.dev/docs/json">JSON round-trips</a>, and <a class="" href="https://foundations.typr.dev/docs/query-analysis">query analysis</a> verification:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">record</span><span class="token plain"> </span><span class="token class-name">Product</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> id</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> name</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">BigDecimal</span><span class="token plain"> price</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Optional</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Instant</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> createdAt</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">RowCodecNamed</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Product</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> productCodec </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">RowCodec</span><span class="token punctuation" style="color:#393A34">.</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Product</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token function" style="color:#d73a49">namedBuilder</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">field</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"id"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">PgTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">int4</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Product</span><span class="token operator" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">id</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">field</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"name"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">PgTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">text</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Product</span><span class="token operator" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">name</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">field</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"price"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">PgTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">numeric</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Product</span><span class="token operator" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">price</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">field</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"created_at"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">PgTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">timestamptz</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">opt</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token class-name">Product</span><span class="token operator" style="color:#393A34">::</span><span class="token function" style="color:#d73a49">createdAt</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">build</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">Product</span><span class="token operator" style="color:#393A34">::</span><span class="token keyword" style="color:#00009f">new</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><code>.opt()</code> on <code>timestamptz</code> declares a nullable column — the type becomes <code>Optional&lt;Instant&gt;</code>. Forget it on a nullable column and Query Analysis catches it. If the column isn't nullable, the type is <code>Instant</code> — no null check needed.</p>
<p>Named codecs generate SQL for you:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">// SELECT id, name, price, created_at</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Fragment</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">of</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"SELECT "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">productCodec</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">columnList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">" FROM product"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// INSERT INTO product (id, name, price, created_at) VALUES (?, ?, ?, ?)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Fragment</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">insertInto</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"product"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> productCodec</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>Codecs <a class="" href="https://foundations.typr.dev/docs/row-codecs#composing-codecs-for-joins">compose for joins</a> — inner joins give you <code>Tuple2&lt;A, B&gt;</code>, left joins wrap the right side in <code>Optional</code>. If all columns on the right are null, you get <code>Optional.empty()</code>. This isn't a convention — it's in the type.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="six-databases-full-type-fidelity">Six Databases, Full Type Fidelity<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#six-databases-full-type-fidelity" class="hash-link" aria-label="Direct link to Six Databases, Full Type Fidelity" title="Direct link to Six Databases, Full Type Fidelity" translate="no">​</a></h2>
<p>Each database has its own <a class="" href="https://foundations.typr.dev/docs/database-types">typed hierarchy</a>. Not a lowest-common-denominator abstraction — the full type system of each database, modeled exactly:</p>
<p><a class="" href="https://foundations.typr.dev/docs/postgresql"><strong>PostgreSQL</strong></a> — arrays, ranges, JSON, geometric types, network types, text search, composite types, enums, domains.</p>
<p><a class="" href="https://foundations.typr.dev/docs/duckdb"><strong>DuckDB</strong></a> — <code>LIST</code>, <code>MAP</code>, <code>STRUCT</code>, <code>UNION</code>, <code>ENUM</code>, unsigned integers, <code>HUGEINT</code>, <code>INTERVAL</code>, JSON, UUID.</p>
<p><a class="" href="https://foundations.typr.dev/docs/oracle"><strong>Oracle</strong></a> — <code>OBJECT</code> types, <code>NESTED TABLE</code>, <code>VARRAY</code>, <code>XMLTYPE</code>, intervals, LOBs, <code>RAW</code>, <code>ROWID</code>.</p>
<p><a class="" href="https://foundations.typr.dev/docs/mariadb"><strong>MariaDB/MySQL</strong></a> — <code>SET</code>, <code>ENUM</code>, JSON, unsigned integers, spatial types, <code>INET4</code>, <code>INET6</code>, <code>YEAR</code>.</p>
<p><a class="" href="https://foundations.typr.dev/docs/sqlserver"><strong>SQL Server</strong></a> — <code>GEOGRAPHY</code>, <code>GEOMETRY</code>, <code>HIERARCHYID</code>, <code>DATETIMEOFFSET</code>, <code>SQL_VARIANT</code>, <code>VECTOR</code>, XML.</p>
<p><a class="" href="https://foundations.typr.dev/docs/db2"><strong>DB2</strong></a> — <code>DECFLOAT</code>, graphic types, XML, <code>ROWID</code>, high-precision <code>TIMESTAMP(p)</code>.</p>
<p>PostgreSQL composite types become records with typed fields. DuckDB structs and maps work the same way. Oracle OBJECT types, too. Each database's unique capabilities are first-class citizens.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="fragments-composable-sql">Fragments: Composable SQL<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#fragments-composable-sql" class="hash-link" aria-label="Direct link to Fragments: Composable SQL" title="Direct link to Fragments: Composable SQL" translate="no">​</a></h2>
<p>A <a class="" href="https://foundations.typr.dev/docs/fragments"><code>Fragment</code></a> is an immutable piece of SQL with typed, bound parameters. You compose fragments like functions:</p>
<div class="language-kotlin codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-kotlin codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">fun</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">byName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">name</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> String</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Fragment </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    sql </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token string-literal singleline string" style="color:#e3116c">"name LIKE </span><span class="token string-literal singleline interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token string-literal singleline interpolation expression">SqlServerTypes</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">.</span><span class="token string-literal singleline interpolation expression function" style="color:#d73a49">nvarchar</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">(</span><span class="token string-literal singleline interpolation expression">name</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">)</span><span class="token string-literal singleline interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token string-literal singleline string" style="color:#e3116c">"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">fun</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">cheaperThan</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">max</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> BigDecimal</span><span class="token punctuation" style="color:#393A34">)</span><span class="token operator" style="color:#393A34">:</span><span class="token plain"> Fragment </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    sql </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token string-literal singleline string" style="color:#e3116c">"price &lt; </span><span class="token string-literal singleline interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token string-literal singleline interpolation expression">SqlServerTypes</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">.</span><span class="token string-literal singleline interpolation expression function" style="color:#d73a49">decimal</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">(</span><span class="token string-literal singleline interpolation expression">max</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">)</span><span class="token string-literal singleline interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token string-literal singleline string" style="color:#e3116c">"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">val</span><span class="token plain"> filters </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">listOfNotNull</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">byName</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string-literal singleline string" style="color:#e3116c">"%widget%"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    maxPrice</span><span class="token operator" style="color:#393A34">?</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">let</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">cheaperThan</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">it</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">val</span><span class="token plain"> orders </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> sql </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token string-literal singleline string" style="color:#e3116c">"SELECT * FROM orders </span><span class="token string-literal singleline interpolation interpolation-punctuation punctuation" style="color:#393A34">${</span><span class="token string-literal singleline interpolation expression">Fragment</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">.</span><span class="token string-literal singleline interpolation expression function" style="color:#d73a49">whereAnd</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">(</span><span class="token string-literal singleline interpolation expression">filters</span><span class="token string-literal singleline interpolation expression punctuation" style="color:#393A34">)</span><span class="token string-literal singleline interpolation interpolation-punctuation punctuation" style="color:#393A34">}</span><span class="token string-literal singleline string" style="color:#e3116c">"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">query</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">orderCodec</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">run</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">conn</span><span class="token punctuation" style="color:#393A34">)</span><br></span></code></pre></div></div>
<p>Parameters are always bound — never concatenated. The <code>${}</code> syntax creates prepared statement parameters. Fragment references like <code>Fragment.whereAnd()</code> splice SQL directly. The library knows the difference.</p>
<p>Java and Scala get the same composability through the builder API and Scala's <code>sql""</code> interpolator.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="operations-and-templates">Operations and Templates<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#operations-and-templates" class="hash-link" aria-label="Direct link to Operations and Templates" title="Direct link to Operations and Templates" translate="no">​</a></h2>
<p>Calling <code>.query()</code> or <code>.update()</code> on a fragment gives you an <a class="" href="https://foundations.typr.dev/docs/operations"><code>Operation&lt;T&gt;</code></a> — a database action that produces a typed result. Nothing runs until you say so:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">Operation</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Product</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> findAll </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Fragment</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">of</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"SELECT "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">productCodec</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">columnList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">append</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">" FROM product ORDER BY name"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">query</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">productCodec</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">all</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Product</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> products </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> findAll</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">transact</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><a class="" href="https://foundations.typr.dev/docs/composing-operations">Operations compose</a>. Combine independent queries with <code>.combineWith()</code>. Chain dependent operations with <code>.then()</code>. Find-or-create with <code>Operation.ifEmpty()</code>. Every combinator produces a new <code>Operation</code> — still just a value, still composable, still analyzable.</p>
<p><a class="" href="https://foundations.typr.dev/docs/templates">Templates</a> separate SQL structure from parameter values — define the shape once, fill it many times:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">Template</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">Optional</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">User</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> findByEmail </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Fragment</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">of</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"SELECT id, name, email FROM users WHERE email = "</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">param</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">PgTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">text</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">query</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">userCodec</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">maxOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Optional</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">User</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> alice </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> findByEmail</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">on</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"alice@example.com"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">transact</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>Templates support dynamic SQL through <code>.optionally()</code> and batch execution via <code>.onMany()</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="built-in-json-codecs">Built-in JSON Codecs<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#built-in-json-codecs" class="hash-link" aria-label="Direct link to Built-in JSON Codecs" title="Direct link to Built-in JSON Codecs" translate="no">​</a></h2>
<p>Your <code>RowCodec</code> doubles as a <a class="" href="https://foundations.typr.dev/docs/json">JSON codec</a> with zero extra code:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token class-name">DuckDbType</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderLine</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> linesType </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">DuckDbTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">jsonArrayEncodedList</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">lineCodec</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">// Aggregate child rows as JSON — one query instead of N+1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">List</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">OrderLine</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> lines </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token class-name">Fragment</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">of</span><span class="token punctuation" style="color:#393A34">(</span><span class="token triple-quoted-string string" style="color:#e3116c">"""</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    SELECT json_group_array(json_array(product, qty, price))</span><br></span><span class="token-line" style="color:#393A34"><span class="token triple-quoted-string string" style="color:#e3116c">    FROM order_lines WHERE customer_id = """</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">value</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">DuckDbTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">integer</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> customerId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">query</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">RowCodec</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">of</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">linesType</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">exactlyOne</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">transact</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p>Same types for result sets and JSON. No separate deserialization. Works with <code>json_agg()</code> (PostgreSQL), <code>JSON_ARRAYAGG()</code> (MariaDB, Oracle, DB2), <code>json_group_array()</code> (DuckDB), and <code>FOR JSON PATH</code> (SQL Server).</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="type-safe-stored-procedures">Type-Safe Stored Procedures<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#type-safe-stored-procedures" class="hash-link" aria-label="Direct link to Type-Safe Stored Procedures" title="Direct link to Type-Safe Stored Procedures" translate="no">​</a></h2>
<p>Define a <a class="" href="https://foundations.typr.dev/docs/stored-procedures">procedure</a> once — the builder tracks IN and OUT types statically:</p>
<div class="language-java codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-java codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">static</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">final</span><span class="token plain"> </span><span class="token class-name">DbProcedure</span><span class="token class-name punctuation" style="color:#393A34">.</span><span class="token class-name">Def1_2</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">Integer</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> getUser </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">DbProcedure</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">define</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"get_user_by_id"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">input</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">PgTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">int4</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">out</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">PgTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">text</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">out</span><span class="token punctuation" style="color:#393A34">(</span><span class="token class-name">PgTypes</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">text</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">build</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token class-name">Tuple2</span><span class="token generics punctuation" style="color:#393A34">&lt;</span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">,</span><span class="token generics"> </span><span class="token generics class-name">String</span><span class="token generics punctuation" style="color:#393A34">&gt;</span><span class="token plain"> result </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> getUser</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">call</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">userId</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token function" style="color:#d73a49">transact</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">tx</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><br></span></code></pre></div></div>
<p><code>Def1_2</code> encodes the shape: 1 input, 2 outputs. Wrong argument types or missing parameters are compile errors. Functions work too, using <code>SELECT</code> instead of <code>CALL</code>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="production-ready">Production Ready<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#production-ready" class="hash-link" aria-label="Direct link to Production Ready" title="Direct link to Production Ready" translate="no">​</a></h2>
<p>Foundations JDBC is derived from code that has seen real production use, but it has been substantially rewritten and rearchitected into what you see today. Everything is thoroughly tested, but as a fresh release there may be rough edges — we'd rather ship and iterate than wait for perfection. It ships with everything you need:</p>
<ul>
<li class=""><a class="" href="https://foundations.typr.dev/docs/connection-pooling"><strong>Connection Pooling</strong></a> — HikariCP integration with typed config builders.</li>
<li class=""><a class="" href="https://foundations.typr.dev/docs/spring-boot"><strong>Spring Boot</strong></a> — Auto-configured <code>Transactor</code> bean. <code>@Transactional</code> just works.</li>
<li class=""><a class="" href="https://foundations.typr.dev/docs/observability"><strong>Observability</strong></a> — Query listeners, <code>.named()</code> comments visible in <code>pg_stat_activity</code>, interpolated SQL for debugging. <a class="" href="https://foundations.typr.dev/docs/opentelemetry">OpenTelemetry</a> module with automatic spans and pool metrics.</li>
<li class=""><a class="" href="https://foundations.typr.dev/docs/virtual-threads"><strong>Virtual Threads</strong></a> — Blocking API works naturally with JDK 21+ virtual threads. No suspend wrappers, no reactive adapters.</li>
<li class=""><strong>Streaming</strong> — <a class="" href="https://foundations.typr.dev/docs/streaming-reads">Cursor-based reads</a> for large result sets. PostgreSQL <a class="" href="https://foundations.typr.dev/docs/streaming-inserts">COPY protocol</a> for bulk loading.</li>
<li class=""><a class="" href="https://foundations.typr.dev/docs/testing"><strong>Testing</strong></a> — <code>testStrategy()</code> rolls back instead of committing. Tests run against real SQL without leaving data behind.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="performance">Performance<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#performance" class="hash-link" aria-label="Direct link to Performance" title="Direct link to Performance" translate="no">​</a></h2>
<p>We <a class="" href="https://foundations.typr.dev/docs/benchmarks">measured mapping overhead</a> against other popular libraries. In-memory DuckDB, 15-column rows, pure framework overhead:</p>
<table><thead><tr><th style="text-align:right">Rows</th><th style="text-align:right">Raw JDBC</th><th style="text-align:right">Foundations</th><th style="text-align:right">Hibernate (entity)</th><th style="text-align:right">JDBI</th><th style="text-align:right">JdbcTemplate</th></tr></thead><tbody><tr><td style="text-align:right">1</td><td style="text-align:right">289 us</td><td style="text-align:right">384 us</td><td style="text-align:right">775 us</td><td style="text-align:right">415 us</td><td style="text-align:right">297 us</td></tr><tr><td style="text-align:right">1,000</td><td style="text-align:right">6.18 ms</td><td style="text-align:right">5.79 ms</td><td style="text-align:right">9.03 ms</td><td style="text-align:right">6.65 ms</td><td style="text-align:right">6.41 ms</td></tr><tr><td style="text-align:right">100,000</td><td style="text-align:right">570 ms</td><td style="text-align:right">581 ms</td><td style="text-align:right">688 ms</td><td style="text-align:right">582 ms</td><td style="text-align:right">586 ms</td></tr></tbody></table>
<p>Foundations JDBC sits right next to raw JDBC. At scale, the difference vanishes into noise. Full type safety and query analysis at essentially zero cost.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="java-kotlin-scala">Java, Kotlin, Scala<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#java-kotlin-scala" class="hash-link" aria-label="Direct link to Java, Kotlin, Scala" title="Direct link to Java, Kotlin, Scala" translate="no">​</a></h2>
<p>The core library is Java 21. Kotlin and Scala get dedicated wrapper modules:</p>
<ul>
<li class=""><strong>Java</strong> — <code>Optional&lt;T&gt;</code> for nullable columns, builder pattern, <code>Tuple</code> for joins.</li>
<li class=""><strong>Kotlin</strong> — <code>T?</code> for nullable columns, <a class="" href="https://foundations.typr.dev/docs/kotlin-interpolation"><code>sql { }</code> interpolation</a>, <code>Pair</code> for joins.</li>
<li class=""><strong>Scala 3</strong> — <code>Option[T]</code> for nullable columns, <code>sql""</code> interpolation, tuples for joins.</li>
</ul>
<p>Same concepts. Same capabilities. Each language's idioms respected.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="get-started">Get Started<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#get-started" class="hash-link" aria-label="Direct link to Get Started" title="Direct link to Get Started" translate="no">​</a></h2>
<p>Head to the <a class="" href="https://foundations.typr.dev/docs/">Getting Started guide</a> for setup instructions and your first query. Source code on <a href="https://github.com/typr-dev/foundations-jdbc" target="_blank" rel="noopener noreferrer" class="">GitHub</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-next">What's Next<a href="https://foundations.typr.dev/blog/introducing-foundations-jdbc#whats-next" class="hash-link" aria-label="Direct link to What's Next" title="Direct link to What's Next" translate="no">​</a></h2>
<p>Two things are coming that will change how you use Foundations JDBC.</p>
<p><strong>World-class codegen with a SQL DSL.</strong> Generate all the RowCodecs, type definitions, and repository scaffolding directly from your database schema. Write queries in a type-safe SQL DSL that composes like the language it's embedded in.</p>
<p><strong>A native PostgreSQL driver for the JVM.</strong> We've been working on something that fundamentally changes what's possible with PostgreSQL on the JVM. It bypasses JDBC entirely, speaks the PostgreSQL wire protocol directly, and unlocks a class of optimizations that no connection pool or driver can offer today. The same Fragments, RowCodecs, and Operations you write today will run on it without changing a line of code.</p>
<p>Stay tuned.</p>]]></content:encoded>
            <category>release</category>
            <category>announcement</category>
        </item>
    </channel>
</rss>