Skip to content

Commit 7a10ed5

Browse files
committed
site: fix C#/Java/Kotlin code examples to match real generator output
An audit of all three ports (the launch review only covered TS+Python) found the example blocks — which the page headlines as "what every port actually generates" — diverged from real output: - C#: regenerated from real `dotnet meta` output — nested lowercase enum, Data Annotations ([Table]/[Key]/[Column]/[Required]/[MaxLength]/[MinLength]), `class` (not partial/record), nullable CreatedAt, real DbContext/OnModelCreating. - Java: enum members lowercase-verbatim + nested in the DTO record; controller uses the real cross-port envelope (ResponseEntity<?>, limit/offset/sort/withCount, get not findById, update = PATCH/PUT JsonNode) instead of a Spring-Data Page/Pageable shape the tool never emits. - Kotlin: SubscriberTable text("name") (not varchar 255), enum width 64 (not 20), instantWithTimeZone (not timestamp); enum members lowercase; comparison table no longer claims "@serializable data classes" (entities are plain). - Intro/comparison prose: "records for C#" → classes; dropped "Postgres DDL (C#)". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XeGSV3StPCcJGZNNJ4ZfAb
1 parent 09ab677 commit 7a10ed5

1 file changed

Lines changed: 39 additions & 34 deletions

File tree

www/index.html

Lines changed: 39 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ <h2 class="section-label">Four pillars. All shipping.</h2>
9696
<div class="pillars-grid">
9797
<article class="pillar">
9898
<h3>Codegen</h3>
99-
<p>One metadata model → idiomatic native code in five languages: <strong>Drizzle + Zod + Fastify/Hono</strong> (TS), <strong>Spring REST + DTO + JPA</strong> (Java), <strong>Exposed + KotlinPoet + Spring</strong> (Kotlin), <strong>EF Core + ASP.NET + Postgres DDL</strong> (C#), <strong>Pydantic + FastAPI</strong> (Python). Hand-edit-preserving regen via three-way merge.</p>
99+
<p>One metadata model → idiomatic native code in five languages: <strong>Drizzle + Zod + Fastify/Hono</strong> (TS), <strong>Spring REST + DTO + JPA</strong> (Java), <strong>Exposed + KotlinPoet + Spring</strong> (Kotlin), <strong>EF Core + ASP.NET</strong> (C#), <strong>Pydantic + FastAPI</strong> (Python). Hand-edit-preserving regen via three-way merge.</p>
100100
</article>
101101
<article class="pillar">
102102
<h3>Runtime metadata</h3>
@@ -230,7 +230,7 @@ <h2 class="section-label">Five ports. All installable today.</h2>
230230
<!-- Canonical example: one schema → five languages -->
231231
<section class="example" id="example">
232232
<h2 class="section-label">From one schema, five languages.</h2>
233-
<p class="example-intro">A typed entity in metadata, side-by-side with what every port actually generates. Each output is idiomatic for that language — Drizzle + Zod for TypeScript, JPA + Spring records for Java, Exposed + KotlinPoet data classes for Kotlin, EF Core + ASP.NET records for C#, Pydantic + FastAPI for Python. Same metadata; five idiomatic outputs; conformance-gated to byte-identical canonical form.</p>
233+
<p class="example-intro">A typed entity in metadata, side-by-side with what every port actually generates. Each output is idiomatic for that language — Drizzle + Zod for TypeScript, JPA + Spring records for Java, Exposed + KotlinPoet data classes for Kotlin, EF Core + ASP.NET classes for C#, Pydantic + FastAPI for Python. Same metadata; five idiomatic outputs; conformance-gated to byte-identical canonical form.</p>
234234

235235
<p class="example-section-label">The source: one YAML file in <code>metaobjects/</code></p>
236236
<pre class="example-code"><code><span class="comment"># metaobjects/meta.subscriber.yaml</span>
@@ -273,7 +273,7 @@ <h2 class="section-label">From one schema, five languages.</h2>
273273
<span class="keyword">export type</span> Subscriber = <span class="keyword">typeof</span> subscribers.$inferSelect;
274274
<span class="keyword">export type</span> SubscriberInsert = z.infer&lt;<span class="keyword">typeof</span> SubscriberInsertSchema&gt;;</code></pre>
275275

276-
<p class="example-section-label">Java — Spring + JPA record from <code>codegen-spring</code></p>
276+
<p class="example-section-label">Java — Spring REST + DTO record from <code>codegen-spring</code></p>
277277
<pre class="example-code"><code><span class="comment">// generated/SubscriberDto.java</span>
278278
<span class="keyword">package</span> acme;
279279

@@ -283,24 +283,25 @@ <h2 class="section-label">From one schema, five languages.</h2>
283283
String name,
284284
SubscriberStatus status,
285285
java.time.Instant createdAt
286-
) {}
287-
288-
<span class="keyword">public enum</span> SubscriberStatus { ACTIVE, PAUSED, CANCELLED }
286+
) {
287+
<span class="keyword">public enum</span> SubscriberStatus { active, paused, cancelled }
288+
}
289289

290290
<span class="comment">// generated/SubscriberController.java (excerpt)</span>
291291
@RestController
292292
@RequestMapping(<span class="string">"/api/subscribers"</span>)
293293
<span class="keyword">public class</span> SubscriberController {
294294
@GetMapping(<span class="string">"/{id}"</span>)
295-
<span class="keyword">public</span> SubscriberDto findById(@PathVariable Long id) { <span class="comment">/* ... */</span> }
295+
<span class="keyword">public</span> ResponseEntity&lt;?&gt; get(@PathVariable Long id) { <span class="comment">/* ... */</span> }
296296

297-
@GetMapping
298-
<span class="keyword">public</span> Page&lt;SubscriberDto&gt; list(@RequestParam Map&lt;String, String&gt; filter,
299-
Pageable pageable) { <span class="comment">/* ... */</span> }
297+
@GetMapping <span class="comment">// cross-port envelope: limit/offset + optional withCount</span>
298+
<span class="keyword">public</span> ResponseEntity&lt;?&gt; list(@RequestParam Integer limit, Integer offset,
299+
String sort, Integer withCount) { <span class="comment">/* ... */</span> }
300300

301-
@PostMapping <span class="keyword">public</span> SubscriberDto create(@RequestBody SubscriberDto dto) { <span class="comment">/* ... */</span> }
302-
@PutMapping(<span class="string">"/{id}"</span>) <span class="keyword">public</span> SubscriberDto update(...) { <span class="comment">/* ... */</span> }
303-
@DeleteMapping(<span class="string">"/{id}"</span>) <span class="keyword">public void</span> delete(@PathVariable Long id) { <span class="comment">/* ... */</span> }
301+
@PostMapping <span class="keyword">public</span> ResponseEntity&lt;?&gt; create(@RequestBody SubscriberDto dto) { <span class="comment">/* ... */</span> }
302+
@RequestMapping(value = <span class="string">"/{id}"</span>, method = { PATCH, PUT })
303+
<span class="keyword">public</span> ResponseEntity&lt;?&gt; update(@PathVariable Long id, @RequestBody JsonNode patch) { <span class="comment">/* ... */</span> }
304+
@DeleteMapping(<span class="string">"/{id}"</span>) <span class="keyword">public</span> ResponseEntity&lt;?&gt; delete(@PathVariable Long id) { <span class="comment">/* ... */</span> }
304305
}</code></pre>
305306

306307
<p class="example-section-label">Kotlin — Exposed + KotlinPoet data class from <code>codegen-kotlin</code></p>
@@ -319,43 +320,47 @@ <h2 class="section-label">From one schema, five languages.</h2>
319320
)
320321

321322
@Serializable
322-
<span class="keyword">public enum class</span> SubscriberStatus { ACTIVE, PAUSED, CANCELLED }
323+
<span class="keyword">public enum class</span> SubscriberStatus { active, paused, cancelled }
323324

324325
<span class="comment">// generated/SubscriberTable.kt</span>
325326
<span class="keyword">object</span> SubscriberTable : Table(<span class="string">"subscribers"</span>) {
326327
<span class="keyword">val</span> id = long(<span class="string">"id"</span>).autoIncrement()
327328
<span class="keyword">val</span> email = varchar(<span class="string">"email"</span>, 320)
328-
<span class="keyword">val</span> name = varchar(<span class="string">"name"</span>, 255).nullable()
329-
<span class="keyword">val</span> status = enumerationByName(<span class="string">"status"</span>, 20, SubscriberStatus::class)
330-
<span class="keyword">val</span> createdAt = timestamp(<span class="string">"created_at"</span>).nullable()
329+
<span class="keyword">val</span> name = text(<span class="string">"name"</span>).nullable()
330+
<span class="keyword">val</span> status = enumerationByName(<span class="string">"status"</span>, 64, SubscriberStatus::class)
331+
<span class="keyword">val</span> createdAt = instantWithTimeZone(<span class="string">"created_at"</span>).nullable()
331332

332333
<span class="keyword">override val</span> primaryKey = PrimaryKey(id)
333334
}</code></pre>
334335

335336
<p class="example-section-label">C#.NET — EF Core + ASP.NET from <code>MetaObjects.Codegen</code></p>
336-
<pre class="example-code"><code><span class="comment">// generated/Subscriber.cs</span>
337+
<pre class="example-code"><code><span class="comment">// generated/Subscriber.g.cs</span>
338+
<span class="keyword">using</span> System.ComponentModel.DataAnnotations;
339+
<span class="keyword">using</span> System.ComponentModel.DataAnnotations.Schema;
337340
<span class="keyword">namespace</span> Acme;
338341

339-
<span class="keyword">public partial class</span> Subscriber {
342+
[Table(<span class="string">"subscribers"</span>)]
343+
<span class="keyword">public class</span> Subscriber {
344+
<span class="keyword">public enum</span> SubscriberStatus { active, paused, cancelled }
345+
346+
[Key] [Column(<span class="string">"id"</span>)]
340347
<span class="keyword">public long</span> Id { <span class="keyword">get; set;</span> }
341-
<span class="keyword">public string</span> Email { <span class="keyword">get; set;</span> } = <span class="keyword">null!</span>;
342-
<span class="keyword">public string?</span> Name { <span class="keyword">get; set;</span> }
343-
<span class="keyword">public</span> SubscriberStatus Status { <span class="keyword">get; set;</span> }
344-
<span class="keyword">public</span> DateTimeOffset CreatedAt { <span class="keyword">get; set;</span> }
345-
}
346348

347-
<span class="keyword">public enum</span> SubscriberStatus { Active, Paused, Cancelled }
349+
[Column(<span class="string">"email"</span>)] [Required(AllowEmptyStrings = <span class="keyword">true</span>)] [MaxLength(320)] [MinLength(1)]
350+
<span class="keyword">public string</span> Email { <span class="keyword">get; set;</span> } = <span class="keyword">default!</span>;
351+
352+
[Column(<span class="string">"name"</span>)] <span class="keyword">public string?</span> Name { <span class="keyword">get; set;</span> }
353+
[Column(<span class="string">"status"</span>)] <span class="keyword">public</span> SubscriberStatus Status { <span class="keyword">get; set;</span> }
354+
[Column(<span class="string">"createdAt"</span>)] <span class="keyword">public</span> DateTimeOffset? CreatedAt { <span class="keyword">get; set;</span> }
355+
}
348356

349-
<span class="comment">// generated/AppDbContext.cs (excerpt)</span>
350-
<span class="keyword">public partial class</span> AppDbContext : DbContext {
351-
<span class="keyword">public</span> DbSet&lt;Subscriber&gt; Subscribers =&gt; Set&lt;Subscriber&gt;();
357+
<span class="comment">// generated/AppDbContext.g.cs (excerpt)</span>
358+
<span class="keyword">public class</span> AppDbContext : DbContext {
359+
<span class="keyword">public</span> DbSet&lt;Subscriber&gt; Subscribers { <span class="keyword">get; set;</span> } = <span class="keyword">default!</span>;
352360

353361
<span class="keyword">protected override void</span> OnModelCreating(ModelBuilder b) {
354-
b.Entity&lt;Subscriber&gt;(e =&gt; {
355-
e.HasKey(s =&gt; s.Id);
356-
e.Property(s =&gt; s.Email).IsRequired().HasMaxLength(320);
357-
e.Property(s =&gt; s.Status).HasConversion&lt;<span class="keyword">string</span>&gt;();
358-
});
362+
b.Entity&lt;Subscriber&gt;().Property(x =&gt; x.Status).HasConversion&lt;<span class="keyword">string</span>&gt;();
363+
b.Entity&lt;Subscriber&gt;().Property(x =&gt; x.CreatedAt).HasColumnType(<span class="string">"timestamp with time zone"</span>);
359364
}
360365
}</code></pre>
361366

@@ -505,7 +510,7 @@ <h2 class="section-label">How MetaObjects compares.</h2>
505510
<td><strong>Kotlin</strong></td>
506511
<td><a href="https://github.com/JetBrains/Exposed">Exposed</a>, <a href="https://ktor.io">Ktor</a> + jOOQ, <a href="https://github.com/Kotlin/kotlinx.serialization">kotlinx.serialization</a></td>
507512
<td>Idiomatic Kotlin SQL DSL (Exposed). Solid web stack (Ktor). First-class coroutines.</td>
508-
<td>KotlinPoet-generated <code>@Serializable</code> data classes + Exposed Tables from the same metamodel that drives the Java / TS / Python / C# stacks. Same Kotlin idioms; cross-port lockstep.</td>
513+
<td>KotlinPoet-generated data classes + Exposed Tables from the same metamodel that drives the Java / TS / Python / C# stacks. Same Kotlin idioms; cross-port lockstep.</td>
509514
</tr>
510515
<tr>
511516
<td><strong>C#.NET</strong></td>

0 commit comments

Comments
 (0)