Skip to content

Commit 6c071de

Browse files
committed
WIP
1 parent 5664b98 commit 6c071de

File tree

10 files changed

+210
-43
lines changed

10 files changed

+210
-43
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.stubbornjava.cms.server.post;
2+
3+
import java.time.LocalDate;
4+
import java.util.List;
5+
6+
import lombok.Builder;
7+
import lombok.Singular;
8+
import lombok.Value;
9+
10+
@Value
11+
@Builder(toBuilder=true)
12+
public class PostMeta {
13+
private final long postId;
14+
private final int appId;
15+
private final String title;
16+
private final String slug;
17+
private final LocalDate dateCreated;
18+
@Singular private final List<String> tags;
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.stubbornjava.cms.server.post;
2+
3+
import java.util.Set;
4+
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.Singular;
8+
9+
@Data
10+
@Builder(toBuilder=true)
11+
public class PostSearch {
12+
private final int appId;
13+
@Singular private final Set<Long> excludePostIds;
14+
@Singular private final Set<String> tagNames;
15+
private final Integer limit;
16+
}

stubbornjava-cms-server/src/main/java/com/stubbornjava/cms/server/post/PostTags.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,58 @@
11
package com.stubbornjava.cms.server.post;
22

3+
import java.util.Arrays;
4+
import java.util.Collection;
35
import java.util.List;
4-
import java.util.Set;
6+
import java.util.Map;
57

68
import org.jooq.DSLContext;
9+
import org.jooq.Field;
710
import org.jooq.lambda.Seq;
811

12+
import com.google.common.collect.Lists;
13+
import com.google.common.collect.Multimap;
14+
import com.stubbornjava.cms.server.CMSBootstrap;
15+
import com.stubbornjava.cms.server.CmsDSLs;
916
import com.stubbornjava.cms.server.generated.Tables;
17+
import com.stubbornjava.cms.server.generated.tables.PostTable;
18+
import com.stubbornjava.cms.server.generated.tables.PostTagLinksTable;
1019
import com.stubbornjava.cms.server.generated.tables.PostTagTable;
1120
import com.stubbornjava.cms.server.generated.tables.records.PostTagLinksRecord;
1221
import com.stubbornjava.cms.server.generated.tables.records.PostTagRecord;
22+
import com.stubbornjava.common.Multimaps;
1323
import com.stubbornjava.common.db.Dao;
1424

1525
public class PostTags {
1626
private PostTags() {}
27+
private static final PostTable post = Tables.POST;
28+
private static final PostTagTable postTag = Tables.POST_TAG;
29+
private static final PostTagLinksTable postTagLinks = Tables.POST_TAG_LINKS;
1730

1831
private static final Dao<PostTagRecord, PostTag, PostTagTable> postTagDao = new Dao<>(Tables.POST_TAG, PostTags::fromRecord, PostTags::toRecord);
1932

2033
public static PostTag create(DSLContext ctx, PostTag tag) {
2134
return postTagDao.insertReturning(ctx, tag);
2235
}
2336

24-
public static List<PostTag> findPostTagsByName(DSLContext ctx, int appId, Set<String> tags) {
37+
public static List<PostTag> findPostTagsByName(DSLContext ctx, int appId, Collection<String> tags) {
2538
return postTagDao.fetch(ctx, pt -> pt.APP_ID.eq(appId)
2639
.and(pt.NAME.in(tags)));
2740
}
2841

42+
public static Multimap<Long, PostTag> findTagsForPosts(DSLContext ctx, int appId, Collection<Long> postIds) {
43+
List<Field<?>> fields = Lists.newArrayList(postTagLinks.POST_ID);
44+
fields.addAll(Arrays.asList(postTag.fields()));
45+
Map<Long, List<PostTag>> tags = ctx.select(fields)
46+
.from(postTag)
47+
.join(postTagLinks)
48+
.on(postTag.POST_TAG_ID.eq(postTagLinks.POST_TAG_ID))
49+
.where(postTagLinks.POST_ID.in(postIds))
50+
.fetchGroups(postTagLinks.POST_ID, record -> {
51+
return PostTags.fromRecord(record.into(postTag));
52+
});
53+
return Multimaps.newListMultimap(tags);
54+
}
55+
2956
/*
3057
* There are some race conditions here if there's two updates
3158
* at the same time but good enough for now.
@@ -52,6 +79,11 @@ static PostTag fromRecord(PostTagRecord record) {
5279
}
5380

5481
public static void main(String[] args) {
55-
82+
CMSBootstrap.run(() -> {
83+
CmsDSLs.transactional().transaction(ctx -> {
84+
Multimap<Long, PostTag> results = findTagsForPosts(ctx, 1, Lists.newArrayList(1L, 2L));
85+
System.out.println();
86+
});
87+
});
5688
}
5789
}

stubbornjava-cms-server/src/main/java/com/stubbornjava/cms/server/post/Posts.java

Lines changed: 116 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,133 @@
11
package com.stubbornjava.cms.server.post;
22

3+
import java.util.Collection;
34
import java.util.List;
5+
import java.util.Optional;
46
import java.util.Set;
57

8+
import org.jooq.Condition;
69
import org.jooq.DSLContext;
10+
import org.jooq.Field;
11+
import org.jooq.impl.DSL;
12+
import org.jooq.lambda.Seq;
713

14+
import com.google.common.collect.Lists;
15+
import com.google.common.collect.Multimap;
816
import com.stubbornjava.cms.server.generated.Tables;
917
import com.stubbornjava.cms.server.generated.tables.PostTable;
18+
import com.stubbornjava.cms.server.generated.tables.PostTagLinksTable;
19+
import com.stubbornjava.cms.server.generated.tables.PostTagTable;
1020
import com.stubbornjava.cms.server.generated.tables.records.PostRecord;
1121
import com.stubbornjava.common.db.Dao;
1222

1323
public class Posts {
1424
private Posts() {}
25+
private static final PostTable post = Tables.POST;
26+
private static final PostTagTable postTag = Tables.POST_TAG;
27+
private static final PostTagLinksTable postTagLinks = Tables.POST_TAG_LINKS;
1528
private static final Dao<PostRecord, Post, PostTable> postDao = new Dao<>(Tables.POST, Posts::fromRecord, Posts::toRecord);
1629

30+
private static final List<Field<?>> postMetaFields = Lists.newArrayList(post.POST_ID, post.APP_ID, post.TITLE, post.SLUG, post.DATE_CREATED);
31+
1732
public static FullPost create(DSLContext ctx, int appId, FullPost fullPost) {
1833
Post post = postFromFull(fullPost);
1934
Post created = postDao.insertReturning(ctx, post);
2035
Set<String> tags = fullPost.getTags();
2136
List<PostTag> postTags = PostTags.findPostTagsByName(ctx, appId, tags);
2237
PostTags.linkTagsToPost(ctx, appId, created.getPostId(), postTags);
23-
return buildFullPost(created);
38+
return buildFullPost(created, postTags);
39+
}
40+
41+
42+
public static List<PostMeta> getRecentPostsExcluding(DSLContext ctx, int appId, Set<Long> excludePostIds) {
43+
PostSearch search = PostSearch.builder()
44+
.appId(appId)
45+
.excludePostIds(excludePostIds)
46+
.limit(10)
47+
.build();
48+
return postSearch(ctx, appId, search);
49+
}
50+
51+
public static List<PostMeta> getRecentPosts(DSLContext ctx, int appId) {
52+
return getRecentPosts(ctx, appId, 10);
53+
}
54+
55+
public static List<PostMeta> getRecentPosts(DSLContext ctx, int appId, int num) {
56+
PostSearch search = PostSearch.builder()
57+
.appId(appId)
58+
.limit(num)
59+
.build();
60+
return postSearch(ctx, appId, search);
61+
}
62+
63+
public static List<PostMeta> getRecentPostsWithTag(DSLContext ctx, int appId, String tag) {
64+
PostSearch search = PostSearch.builder()
65+
.appId(appId)
66+
.tagName(tag)
67+
.limit(50)
68+
.build();
69+
return postSearch(ctx, appId, search);
70+
}
71+
72+
private static List<PostMeta> postSearch(DSLContext ctx, int appId, PostSearch searchRequest) {
73+
Condition condition = DSL.trueCondition();
74+
75+
if (!searchRequest.getExcludePostIds().isEmpty()) {
76+
condition.and(post.POST_ID.notIn(searchRequest.getExcludePostIds()));
77+
}
78+
79+
if (!searchRequest.getTagNames().isEmpty()) {
80+
condition.and(post.POST_ID.in(ctx.select(postTagLinks.POST_ID)
81+
.from(postTag)
82+
.where(postTag.NAME.in(searchRequest.getTagNames()))));
83+
}
84+
85+
int limit = Optional.ofNullable(searchRequest.getLimit()).orElse(50);
86+
87+
List<PostMeta> posts = ctx.select(postMetaFields)
88+
.from(post)
89+
.where(condition)
90+
.orderBy(post.DATE_CREATED.desc(), post.DATE_CREATED_TS.desc())
91+
.limit(limit)
92+
.fetch(record -> Posts.metaFromRecord(record.into(post)));
93+
Multimap<Long, PostTag> tagsByPostId = PostTags.findTagsForPosts(ctx, appId, metaIds(posts));
94+
95+
List<PostMeta> postMetas = Seq.seq(posts).map(p -> {
96+
List<String> tagNames = Seq.seq(tagsByPostId.get(p.getPostId())).map(PostTag::getName).toList();
97+
return p.toBuilder()
98+
.tags(tagNames)
99+
.build();
100+
}).toList();
101+
return postMetas;
102+
}
103+
104+
private static Set<Long> ids(Collection<Post> posts) {
105+
return Seq.seq(posts).map(Post::getPostId).toSet();
106+
}
107+
108+
private static Set<Long> metaIds(Collection<PostMeta> posts) {
109+
return Seq.seq(posts).map(PostMeta::getPostId).toSet();
110+
}
111+
112+
private static List<FullPost> buildFullPosts(DSLContext ctx, List<Post> posts, Multimap<Long, PostTag> tagsByPostId) {
113+
return Seq.seq(posts)
114+
.map(post -> buildFullPost(post, tagsByPostId.get(post.getPostId())))
115+
.toList();
24116
}
25117

26-
static FullPost buildFullPost(Post post) {
118+
private static FullPost buildFullPost(Post post, Collection<PostTag> tags) {
27119
return new FullPost(
28-
post.getPostId(),
29-
post.getAppId(),
30-
post.getTitle(),
31-
post.getSlug(),
32-
post.getMetadesc(),
33-
post.getDraftStatus(),
34-
post.getLastUpdateTs(),
35-
post.getDateCreatedTs(),
36-
post.getDateCreated(),
37-
post.getContentTemplate(),
38-
null);
120+
post.getPostId(),
121+
post.getAppId(),
122+
post.getTitle(),
123+
post.getSlug(),
124+
post.getMetadesc(),
125+
post.getDraftStatus(),
126+
post.getLastUpdateTs(),
127+
post.getDateCreatedTs(),
128+
post.getDateCreated(),
129+
post.getContentTemplate(),
130+
Seq.seq(tags).map(PostTag::getName).toSet());
39131
}
40132

41133
static Post postFromFull(FullPost fullPost) {
@@ -82,4 +174,15 @@ static Post fromRecord(PostRecord record) {
82174
record.getContentTemplate()
83175
);
84176
}
177+
178+
static PostMeta metaFromRecord(PostRecord record) {
179+
return new PostMeta(
180+
record.getPostId(),
181+
record.getAppId(),
182+
record.getTitle(),
183+
record.getSlug(),
184+
record.getDateCreated(),
185+
null
186+
);
187+
}
85188
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.stubbornjava.common;
2+
3+
import java.util.Map;
4+
5+
import com.google.common.collect.ArrayListMultimap;
6+
import com.google.common.collect.Multimap;
7+
8+
public class Multimaps {
9+
private Multimaps() {}
10+
11+
public static <K, V> Multimap<K, V> newListMultimap(Map<K, ? extends Iterable<V>> input) {
12+
Multimap<K, V> multimap = ArrayListMultimap.create();
13+
for (Map.Entry<K, ? extends Iterable<V>> entry : input.entrySet()) {
14+
multimap.putAll(entry.getKey(), entry.getValue());
15+
}
16+
return multimap;
17+
}
18+
}

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/JavaLibRoutes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import org.slf4j.Logger;
66
import org.slf4j.LoggerFactory;
77

8+
import com.stubbornjava.cms.server.post.PostMeta;
89
import com.stubbornjava.common.undertow.Exchange;
910
import com.stubbornjava.webapp.Response;
1011

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/Post.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.stubbornjava.webapp.post;
22

33
import com.fasterxml.jackson.annotation.JsonUnwrapped;
4+
import com.stubbornjava.cms.server.post.PostMeta;
45

56
import lombok.Builder;
67
import lombok.Value;

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/PostMeta.java

Lines changed: 0 additions & 23 deletions
This file was deleted.

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/PostRoutes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.List;
44

5+
import com.stubbornjava.cms.server.post.PostMeta;
56
import com.stubbornjava.common.undertow.Exchange;
67
import com.stubbornjava.webapp.PageRoutes;
78
import com.stubbornjava.webapp.Response;

stubbornjava-webapp/src/main/java/com/stubbornjava/webapp/post/Posts.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.google.common.collect.Maps;
1616
import com.google.common.collect.Multimap;
1717
import com.stubbornjava.cms.server.CmsDSLs;
18+
import com.stubbornjava.cms.server.post.PostMeta;
1819
import com.stubbornjava.common.Resources;
1920
import com.stubbornjava.common.Templating;
2021
import com.stubbornjava.webapp.WebappBoostrap;
@@ -55,10 +56,8 @@ public class Posts {
5556
}
5657
}
5758

58-
public static List<PostMeta> getRecentPostsExcluding(Set<Long> excludeIds) {
59-
return Seq.seq(recentPosts)
60-
.filter(p -> !excludeIds.contains(p.getPostId()))
61-
.limit(10).toList();
59+
public static List<PostMeta> getRecentPostsExcluding(Set<Long> excludePostIds) {
60+
return com.stubbornjava.cms.server.post.Posts.getRecentPostsExcluding(ctx, 1L, excludeIds);
6261
}
6362

6463
public static List<PostMeta> getRecentPosts() {

0 commit comments

Comments
 (0)