From 1fc37673f7cf16226e7084813fcc5980db40f65c Mon Sep 17 00:00:00 2001 From: John Niang Date: Tue, 27 Sep 2022 10:24:15 +0800 Subject: [PATCH] Support running Halo with PostgreSQL (#2472) #### What type of PR is this? /kind feature /area core /milestone 2.0 #### What this PR does / why we need it: Add PostgreSQL script to support running Halo with PostgreSQL database. BTW, there was a weird issue (emty posts even if there are some posts created) while listing Post, and I fixed it in this PR. #### Which issue(s) this PR fixes: Partial Fixes https://github.com/halo-dev/halo/issues/2464 #### Special notes for reviewers Steps to test: 1. Start up PostgreSQL. e.g.: ```yaml version: '3.1' services: db: image: postgres restart: always environment: POSTGRES_PASSWORD: openpostgresql ports: - 5432:5432 adminer: image: adminer restart: always ports: - 8080:8080 ``` ```bash docker-compose -f postgresql.yaml up ``` 2. Start Halo with `postgresql` profile. e.g.: ```bash ./gradlew bootRun --args="--spring.profiles.active=postgresql" ``` 3. Validate the functionality of Halo #### Does this PR introduce a user-facing change? ```release-note None ``` --- .../app/content/impl/PostServiceImpl.java | 89 +++++++++++-------- .../extension/reconciler/PostReconciler.java | 4 +- .../resources/application-postgresql.yaml | 9 ++ src/main/resources/schema-postgresql.sql | 7 ++ 4 files changed, 69 insertions(+), 40 deletions(-) create mode 100644 src/main/resources/application-postgresql.yaml create mode 100644 src/main/resources/schema-postgresql.sql diff --git a/src/main/java/run/halo/app/content/impl/PostServiceImpl.java b/src/main/java/run/halo/app/content/impl/PostServiceImpl.java index 10c759d98..40a3e223e 100644 --- a/src/main/java/run/halo/app/content/impl/PostServiceImpl.java +++ b/src/main/java/run/halo/app/content/impl/PostServiceImpl.java @@ -128,59 +128,70 @@ public class PostServiceImpl implements PostService { private Mono getListedPost(Post post) { Assert.notNull(post, "The post must not be null."); - ListedPost listedPost = new ListedPost(); - listedPost.setPost(post); - return Mono.zip(listTags(post.getSpec().getTags()), - listCategories(post.getSpec().getCategories()), - listContributors(post.getStatusOrDefault().getContributors()) - ) - .map(tuple -> { - List tags = tuple.getT1(); - List categories = tuple.getT2(); - List contributors = tuple.getT3(); - listedPost.setTags(tags); - listedPost.setCategories(categories); - listedPost.setContributors(contributors); + return Mono.just(post) + .map(p -> { + ListedPost listedPost = new ListedPost(); + listedPost.setPost(p); return listedPost; - }); + }) + .flatMap(lp -> setTags(post.getSpec().getTags(), lp)) + .flatMap(lp -> setCategories(post.getSpec().getCategories(), lp)) + .flatMap(lp -> setContributors(post.getStatus().getContributors(), lp)); } - private Mono> listTags(List tagNames) { + private Mono setTags(List tagNames, ListedPost post) { + return listTags(tagNames) + .collectSortedList() + .doOnNext(post::setTags) + .map(tags -> post) + .switchIfEmpty(Mono.defer(() -> Mono.just(post))); + } + + private Mono setCategories(List categoryNames, ListedPost post) { + return listCategories(categoryNames) + .collectSortedList() + .doOnNext(post::setCategories) + .map(categories -> post) + .switchIfEmpty(Mono.defer(() -> Mono.just(post))); + } + + private Mono setContributors(List contributorNames, ListedPost post) { + return listContributors(contributorNames) + .collectSortedList() + .doOnNext(post::setContributors) + .map(contributors -> post) + .switchIfEmpty(Mono.defer(() -> Mono.just(post))); + } + + private Flux listTags(List tagNames) { if (tagNames == null) { - return Mono.empty(); + return Flux.empty(); } - return Flux.fromStream(tagNames.stream() - .map(tagName -> client.fetch(Tag.class, tagName))) - .flatMap(Function.identity()) - .collectList(); + return Flux.fromIterable(tagNames) + .flatMap(tagName -> client.fetch(Tag.class, tagName)); } - private Mono> listCategories(List categoryNames) { + private Flux listCategories(List categoryNames) { if (categoryNames == null) { - return Mono.empty(); + return Flux.empty(); } - return Flux.fromStream(categoryNames.stream() - .map(categoryName -> client.fetch(Category.class, categoryName))) - .flatMap(Function.identity()) - .collectList(); + return Flux.fromIterable(categoryNames) + .flatMap(categoryName -> client.fetch(Category.class, categoryName)); } - private Mono> listContributors(List usernames) { + private Flux listContributors(List usernames) { if (usernames == null) { - return Mono.empty(); + return Flux.empty(); } return Flux.fromIterable(usernames) - .map(username -> client.fetch(User.class, username) - .map(user -> { - Contributor contributor = new Contributor(); - contributor.setName(username); - contributor.setDisplayName(user.getSpec().getDisplayName()); - contributor.setAvatar(user.getSpec().getAvatar()); - return contributor; - }) - ) - .flatMap(Function.identity()) - .collectList(); + .flatMap(username -> client.fetch(User.class, username)) + .map(user -> { + Contributor contributor = new Contributor(); + contributor.setName(user.getMetadata().getName()); + contributor.setDisplayName(user.getSpec().getDisplayName()); + contributor.setAvatar(user.getSpec().getAvatar()); + return contributor; + }); } @Override diff --git a/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java b/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java index 2059be1eb..791126b8c 100644 --- a/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java +++ b/src/main/java/run/halo/app/core/extension/reconciler/PostReconciler.java @@ -122,7 +122,8 @@ public class PostReconciler implements Reconciler { String headSnapshot = post.getSpec().getHeadSnapshot(); contentService.listSnapshots(Snapshot.SubjectRef.of(Post.KIND, name)) .collectList() - .subscribe(snapshots -> { + .blockOptional() + .ifPresent(snapshots -> { List contributors = snapshots.stream() .map(snapshot -> { Set usernames = snapshot.getSpec().getContributors(); @@ -143,6 +144,7 @@ public class PostReconciler implements Reconciler { .ifPresent(snapshot -> { status.setInProgress(!isPublished(snapshot)); }); + }); // handle cancel publish,has released version and published is false and not handled diff --git a/src/main/resources/application-postgresql.yaml b/src/main/resources/application-postgresql.yaml new file mode 100644 index 000000000..d519c62a5 --- /dev/null +++ b/src/main/resources/application-postgresql.yaml @@ -0,0 +1,9 @@ +spring: + r2dbc: + url: r2dbc:pool:postgresql://localhost:5432/halo + username: postgres + password: openpostgresql + sql: + init: + mode: always + platform: postgresql diff --git a/src/main/resources/schema-postgresql.sql b/src/main/resources/schema-postgresql.sql new file mode 100644 index 000000000..96c46af29 --- /dev/null +++ b/src/main/resources/schema-postgresql.sql @@ -0,0 +1,7 @@ +create table if not exists extensions +( + name varchar(255) not null, + data bytea, + version bigint, + primary key (name) +);