blog: Some changes.

Change-Id: Ic2053c65150f3cb9b7e121f4c859a45baf815a4b
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