mirror of https://github.com/halo-dev/halo
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 ```pull/2474/head
parent
264a4330c3
commit
1fc37673f7
|
@ -128,59 +128,70 @@ public class PostServiceImpl implements PostService {
|
||||||
|
|
||||||
private Mono<ListedPost> getListedPost(Post post) {
|
private Mono<ListedPost> getListedPost(Post post) {
|
||||||
Assert.notNull(post, "The post must not be null.");
|
Assert.notNull(post, "The post must not be null.");
|
||||||
ListedPost listedPost = new ListedPost();
|
return Mono.just(post)
|
||||||
listedPost.setPost(post);
|
.map(p -> {
|
||||||
return Mono.zip(listTags(post.getSpec().getTags()),
|
ListedPost listedPost = new ListedPost();
|
||||||
listCategories(post.getSpec().getCategories()),
|
listedPost.setPost(p);
|
||||||
listContributors(post.getStatusOrDefault().getContributors())
|
|
||||||
)
|
|
||||||
.map(tuple -> {
|
|
||||||
List<Tag> tags = tuple.getT1();
|
|
||||||
List<Category> categories = tuple.getT2();
|
|
||||||
List<Contributor> contributors = tuple.getT3();
|
|
||||||
listedPost.setTags(tags);
|
|
||||||
listedPost.setCategories(categories);
|
|
||||||
listedPost.setContributors(contributors);
|
|
||||||
return listedPost;
|
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<List<Tag>> listTags(List<String> tagNames) {
|
private Mono<ListedPost> setTags(List<String> tagNames, ListedPost post) {
|
||||||
|
return listTags(tagNames)
|
||||||
|
.collectSortedList()
|
||||||
|
.doOnNext(post::setTags)
|
||||||
|
.map(tags -> post)
|
||||||
|
.switchIfEmpty(Mono.defer(() -> Mono.just(post)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<ListedPost> setCategories(List<String> categoryNames, ListedPost post) {
|
||||||
|
return listCategories(categoryNames)
|
||||||
|
.collectSortedList()
|
||||||
|
.doOnNext(post::setCategories)
|
||||||
|
.map(categories -> post)
|
||||||
|
.switchIfEmpty(Mono.defer(() -> Mono.just(post)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mono<ListedPost> setContributors(List<String> contributorNames, ListedPost post) {
|
||||||
|
return listContributors(contributorNames)
|
||||||
|
.collectSortedList()
|
||||||
|
.doOnNext(post::setContributors)
|
||||||
|
.map(contributors -> post)
|
||||||
|
.switchIfEmpty(Mono.defer(() -> Mono.just(post)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Flux<Tag> listTags(List<String> tagNames) {
|
||||||
if (tagNames == null) {
|
if (tagNames == null) {
|
||||||
return Mono.empty();
|
return Flux.empty();
|
||||||
}
|
}
|
||||||
return Flux.fromStream(tagNames.stream()
|
return Flux.fromIterable(tagNames)
|
||||||
.map(tagName -> client.fetch(Tag.class, tagName)))
|
.flatMap(tagName -> client.fetch(Tag.class, tagName));
|
||||||
.flatMap(Function.identity())
|
|
||||||
.collectList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<List<Category>> listCategories(List<String> categoryNames) {
|
private Flux<Category> listCategories(List<String> categoryNames) {
|
||||||
if (categoryNames == null) {
|
if (categoryNames == null) {
|
||||||
return Mono.empty();
|
return Flux.empty();
|
||||||
}
|
}
|
||||||
return Flux.fromStream(categoryNames.stream()
|
return Flux.fromIterable(categoryNames)
|
||||||
.map(categoryName -> client.fetch(Category.class, categoryName)))
|
.flatMap(categoryName -> client.fetch(Category.class, categoryName));
|
||||||
.flatMap(Function.identity())
|
|
||||||
.collectList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<List<Contributor>> listContributors(List<String> usernames) {
|
private Flux<Contributor> listContributors(List<String> usernames) {
|
||||||
if (usernames == null) {
|
if (usernames == null) {
|
||||||
return Mono.empty();
|
return Flux.empty();
|
||||||
}
|
}
|
||||||
return Flux.fromIterable(usernames)
|
return Flux.fromIterable(usernames)
|
||||||
.map(username -> client.fetch(User.class, username)
|
.flatMap(username -> client.fetch(User.class, username))
|
||||||
.map(user -> {
|
.map(user -> {
|
||||||
Contributor contributor = new Contributor();
|
Contributor contributor = new Contributor();
|
||||||
contributor.setName(username);
|
contributor.setName(user.getMetadata().getName());
|
||||||
contributor.setDisplayName(user.getSpec().getDisplayName());
|
contributor.setDisplayName(user.getSpec().getDisplayName());
|
||||||
contributor.setAvatar(user.getSpec().getAvatar());
|
contributor.setAvatar(user.getSpec().getAvatar());
|
||||||
return contributor;
|
return contributor;
|
||||||
})
|
});
|
||||||
)
|
|
||||||
.flatMap(Function.identity())
|
|
||||||
.collectList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -122,7 +122,8 @@ public class PostReconciler implements Reconciler<Reconciler.Request> {
|
||||||
String headSnapshot = post.getSpec().getHeadSnapshot();
|
String headSnapshot = post.getSpec().getHeadSnapshot();
|
||||||
contentService.listSnapshots(Snapshot.SubjectRef.of(Post.KIND, name))
|
contentService.listSnapshots(Snapshot.SubjectRef.of(Post.KIND, name))
|
||||||
.collectList()
|
.collectList()
|
||||||
.subscribe(snapshots -> {
|
.blockOptional()
|
||||||
|
.ifPresent(snapshots -> {
|
||||||
List<String> contributors = snapshots.stream()
|
List<String> contributors = snapshots.stream()
|
||||||
.map(snapshot -> {
|
.map(snapshot -> {
|
||||||
Set<String> usernames = snapshot.getSpec().getContributors();
|
Set<String> usernames = snapshot.getSpec().getContributors();
|
||||||
|
@ -143,6 +144,7 @@ public class PostReconciler implements Reconciler<Reconciler.Request> {
|
||||||
.ifPresent(snapshot -> {
|
.ifPresent(snapshot -> {
|
||||||
status.setInProgress(!isPublished(snapshot));
|
status.setInProgress(!isPublished(snapshot));
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// handle cancel publish,has released version and published is false and not handled
|
// handle cancel publish,has released version and published is false and not handled
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
spring:
|
||||||
|
r2dbc:
|
||||||
|
url: r2dbc:pool:postgresql://localhost:5432/halo
|
||||||
|
username: postgres
|
||||||
|
password: openpostgresql
|
||||||
|
sql:
|
||||||
|
init:
|
||||||
|
mode: always
|
||||||
|
platform: postgresql
|
|
@ -0,0 +1,7 @@
|
||||||
|
create table if not exists extensions
|
||||||
|
(
|
||||||
|
name varchar(255) not null,
|
||||||
|
data bytea,
|
||||||
|
version bigint,
|
||||||
|
primary key (name)
|
||||||
|
);
|
Loading…
Reference in New Issue