blog: Some changes.

Change-Id: Ic2053c65150f3cb9b7e121f4c859a45baf815a4b
diff --git a/blog/build.gradle.kts b/blog/build.gradle.kts
index 8316632..6a57a3f 100644
--- a/blog/build.gradle.kts
+++ b/blog/build.gradle.kts
@@ -15,8 +15,8 @@
 
 dependencies {
     implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}"))
-    implementation("io.quarkus:quarkus-resteasy-reactive-jsonb")
-    implementation("io.quarkus:quarkus-resteasy-reactive")
+    implementation("io.quarkus:quarkus-resteasy-jsonb")
+    implementation("io.quarkus:quarkus-resteasy")
     implementation("io.quarkus:quarkus-hibernate-orm-panache")
     implementation("io.quarkus:quarkus-arc")
     implementation("io.quarkus:quarkus-jdbc-postgresql")
diff --git a/blog/gradle.properties b/blog/gradle.properties
index d661789..f4144bf 100644
--- a/blog/gradle.properties
+++ b/blog/gradle.properties
@@ -1,7 +1,7 @@
 quarkusPluginId = io.quarkus
-quarkusPluginVersion = 1.11.3.Final
+quarkusPluginVersion = 1.12.0.Final
 quarkusPlatformGroupId = io.quarkus
 quarkusPlatformArtifactId = quarkus-universe-bom
-quarkusPlatformVersion = 1.11.3.Final
+quarkusPlatformVersion = 1.12.0.Final
 
 hibernateTypesVersion = 2.10.2
diff --git a/blog/pom.xml b/blog/pom.xml
index 0b99b93..4d7be41 100644
--- a/blog/pom.xml
+++ b/blog/pom.xml
@@ -8,14 +8,14 @@
   <properties>
     <compiler-plugin.version>3.8.1</compiler-plugin.version>
     <maven.compiler.parameters>true</maven.compiler.parameters>
-    <maven.compiler.source>11</maven.compiler.source>
-    <maven.compiler.target>11</maven.compiler.target>
+    <maven.compiler.source>15</maven.compiler.source>
+    <maven.compiler.target>15</maven.compiler.target>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-    <quarkus-plugin.version>1.11.3.Final</quarkus-plugin.version>
+    <quarkus-plugin.version>1.12.0.Final</quarkus-plugin.version>
     <quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
     <quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
-    <quarkus.platform.version>1.11.3.Final</quarkus.platform.version>
+    <quarkus.platform.version>1.12.0.Final</quarkus.platform.version>
     <surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
     <hibernate-types.version>2.10.2</hibernate-types.version>
   </properties>
@@ -41,11 +41,11 @@
   <dependencies>
     <dependency>
       <groupId>io.quarkus</groupId>
-      <artifactId>quarkus-resteasy-reactive-jsonb</artifactId>
+      <artifactId>quarkus-resteasy-jsonb</artifactId>
     </dependency>
     <dependency>
       <groupId>io.quarkus</groupId>
-      <artifactId>quarkus-resteasy-reactive</artifactId>
+      <artifactId>quarkus-resteasy</artifactId>
     </dependency>
     <dependency>
       <groupId>io.quarkus</groupId>
@@ -108,6 +108,14 @@
           </systemPropertyVariables>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>15</source>
+          <target>15</target>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
diff --git a/blog/src/main/java/eu/mulk/demos/ReactiveGreetingResource.java b/blog/src/main/java/eu/mulk/demos/ReactiveGreetingResource.java
deleted file mode 100644
index a8fc395..0000000
--- a/blog/src/main/java/eu/mulk/demos/ReactiveGreetingResource.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package eu.mulk.demos;
-
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-
-@Path("/hello-resteasy-reactive")
-public class ReactiveGreetingResource {
-
-    @GET
-    @Produces(MediaType.TEXT_PLAIN)
-    public String hello() {
-        return "Hello";
-    }
-}
diff --git a/blog/src/main/java/eu/mulk/demos/blog/Author.java b/blog/src/main/java/eu/mulk/demos/blog/Author.java
index d9091be..53c21c4 100644
--- a/blog/src/main/java/eu/mulk/demos/blog/Author.java
+++ b/blog/src/main/java/eu/mulk/demos/blog/Author.java
@@ -7,4 +7,10 @@
 public class Author extends PanacheEntity {
 
   public String name;
+
+  public static Author create(String name) {
+    var a = new Author();
+    a.name = name;
+    return a;
+  }
 }
diff --git a/blog/src/main/java/eu/mulk/demos/blog/Category.java b/blog/src/main/java/eu/mulk/demos/blog/Category.java
index a0c3d81..0959d18 100644
--- a/blog/src/main/java/eu/mulk/demos/blog/Category.java
+++ b/blog/src/main/java/eu/mulk/demos/blog/Category.java
@@ -7,4 +7,10 @@
 public class Category extends PanacheEntity {
 
   public String name;
+
+  public static Category create(String name) {
+    var c = new Category();
+    c.name = name;
+    return c;
+  }
 }
diff --git a/blog/src/main/java/eu/mulk/demos/blog/Comment.java b/blog/src/main/java/eu/mulk/demos/blog/Comment.java
index cfcbf84..251d6d8 100644
--- a/blog/src/main/java/eu/mulk/demos/blog/Comment.java
+++ b/blog/src/main/java/eu/mulk/demos/blog/Comment.java
@@ -2,12 +2,31 @@
 
 import io.quarkus.hibernate.orm.panache.PanacheEntity;
 import java.time.Instant;
+import javax.json.bind.annotation.JsonbTransient;
+import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.ManyToOne;
 
 @Entity
 public class Comment extends PanacheEntity {
 
   public String authorName;
+
   public Instant publicationDate;
+
+  @Column(columnDefinition = "TEXT")
   public String text;
+
+  @JsonbTransient
+  @ManyToOne
+  public Post post;
+
+  public static Comment create(Post post, String authorName, String text) {
+    var c = new Comment();
+    c.authorName = authorName;
+    c.publicationDate = Instant.now();
+    c.text = text;
+    c.post = post;
+    return c;
+  }
 }
diff --git a/blog/src/main/java/eu/mulk/demos/blog/DemoDataLoader.java b/blog/src/main/java/eu/mulk/demos/blog/DemoDataLoader.java
new file mode 100644
index 0000000..3ee745a
--- /dev/null
+++ b/blog/src/main/java/eu/mulk/demos/blog/DemoDataLoader.java
@@ -0,0 +1,64 @@
+package eu.mulk.demos.blog;
+
+import static java.util.stream.Collectors.toList;
+
+import io.quarkus.runtime.StartupEvent;
+import java.util.stream.Stream;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+import javax.persistence.EntityManager;
+import javax.transaction.Transactional;
+
+@ApplicationScoped
+public class DemoDataLoader {
+
+  static final int POST_COUNT = 10;
+  static final int COMMENT_COUNT = 3;
+  static final int CATEGORY_COUNT = 2;
+
+  @Inject
+  EntityManager em;
+
+  @Transactional
+  void onStart(@Observes StartupEvent ev) {
+    if (Author.findAll().stream().findAny().isPresent()) {
+      // Already initialized.
+      return;
+    }
+
+    // Authors
+    var mb = Author.create("Matthias Benkard");
+    em.persist(mb);
+
+    // Posts
+    var posts =
+        nat(POST_COUNT).map(x -> Post.create(mb, "Post #%d".formatted(x))).collect(toList());
+    posts.forEach(em::persist);
+
+    // Comments
+    for (var post : posts) {
+      post.comments =
+          nat(COMMENT_COUNT)
+              .map(x -> Comment.create(post, "Anonymous Coward", "First post")).collect(toList());
+      post.comments.forEach(em::persist);
+    }
+
+    // Categories
+    var categories =
+        nat(CATEGORY_COUNT).map(x -> Category.create("Category #%d".formatted(x)))
+            .collect(toList());
+    categories.forEach(em::persist);
+    for (var post : posts) {
+      post.categories = categories;
+    }
+  }
+
+  private static Stream<Integer> nat(int postCount) {
+    return nat().limit(postCount);
+  }
+
+  private static Stream<Integer> nat() {
+    return Stream.iterate(0, x -> x + 1);
+  }
+}
diff --git a/blog/src/main/java/eu/mulk/demos/blog/Post.java b/blog/src/main/java/eu/mulk/demos/blog/Post.java
index a12ba70..3ae3fa0 100644
--- a/blog/src/main/java/eu/mulk/demos/blog/Post.java
+++ b/blog/src/main/java/eu/mulk/demos/blog/Post.java
@@ -26,6 +26,15 @@
   @ManyToMany(fetch = FetchType.LAZY)
   public List<Category> categories;
 
-  @OneToMany(fetch = FetchType.LAZY)
+  @OneToMany(fetch = FetchType.LAZY, mappedBy = "post")
   public List<Comment> comments;
+
+  public static Post create(Author author, String title) {
+    var p = new Post();
+    p.title = title;
+    p.publicationDate = Instant.now();
+    p.body = "";
+    p.author = author;
+    return p;
+  }
 }
diff --git a/blog/src/main/java/eu/mulk/demos/blog/PostResource.java b/blog/src/main/java/eu/mulk/demos/blog/PostResource.java
new file mode 100644
index 0000000..44410cf
--- /dev/null
+++ b/blog/src/main/java/eu/mulk/demos/blog/PostResource.java
@@ -0,0 +1,43 @@
+package eu.mulk.demos.blog;
+
+import java.util.List;
+import javax.transaction.Transactional;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("/posts")
+public class PostResource {
+
+  @GET
+  @Produces(MediaType.TEXT_PLAIN)
+  @Transactional
+  public List<Post> getAll() {
+    return Post.findAll().list();
+  }
+
+  @GET
+  @Produces(MediaType.TEXT_PLAIN)
+  @Transactional
+  @Path("/q1")
+  public List<Post> getAllWithComments() {
+    return Post.find("""
+        SELECT p FROM Post p
+          LEFT JOIN FETCH p.comments 
+        """).list();
+  }
+
+  @GET
+  @Produces(MediaType.TEXT_PLAIN)
+  @Transactional
+  @Path("/q2")
+  public List<Post> getAllWithCommentsAndCategories() {
+    return Post.find("""
+        SELECT p FROM Post p
+          LEFT JOIN FETCH p.comments
+          LEFT JOIN FETCH p.categories
+        """).list();
+  }
+
+}
diff --git a/blog/src/main/resources/application.properties b/blog/src/main/resources/application.properties
index 9ba7752..fbf150e 100644
--- a/blog/src/main/resources/application.properties
+++ b/blog/src/main/resources/application.properties
@@ -4,6 +4,7 @@
 %dev.quarkus.datasource.jdbc.url = jdbc:postgresql://localhost:5432/demo_blog
 %dev.quarkus.datasource.username = demo
 %dev.quarkus.datasource.password =
+
 %dev.quarkus.hibernate-orm.log.sql = true
 %dev.quarkus.hibernate-orm.log.format-sql = true
 %dev.quarkus.hibernate-orm.database.generation = drop-and-create