[Notice] Announcing the End of Demo Server [Read me]
perf: Remake recently visited feature
- Decrease model depth - Make more simpler - Add oldest history deletion logic Sorry for this dirty commit. Some other test logics are combined.
@8c986f757f976b17da349ce15420772d1ba6e80d
--- app/controllers/IssueApp.java
+++ app/controllers/IssueApp.java
... | ... | @@ -226,7 +226,6 @@ |
226 | 226 |
return ok(listData); |
227 | 227 |
} |
228 | 228 |
|
229 |
- @Transactional |
|
230 | 229 |
@With(NullProjectCheckAction.class) |
231 | 230 |
public static Result issue(String ownerName, String projectName, Long number) { |
232 | 231 |
Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
+++ app/models/RecentProject.java
... | ... | @@ -0,0 +1,88 @@ |
1 | +package models; | |
2 | + | |
3 | +import play.db.ebean.Model; | |
4 | +import play.db.ebean.Transactional; | |
5 | + | |
6 | +import javax.annotation.Nonnull; | |
7 | +import javax.persistence.*; | |
8 | +import java.util.ArrayList; | |
9 | +import java.util.Collections; | |
10 | +import java.util.Comparator; | |
11 | +import java.util.List; | |
12 | + | |
13 | +@Entity | |
14 | +public class RecentProject extends Model { | |
15 | + private static final long serialVersionUID = 7306890271871188281L; | |
16 | + public static int MAX_RECENT_LIST_PER_USER = 5; | |
17 | + | |
18 | + public static Finder<Long, RecentProject> find = new Finder<>(Long.class, RecentProject.class); | |
19 | + | |
20 | + @Id | |
21 | + public Long id; | |
22 | + | |
23 | + public Long userId; | |
24 | + public String owner; | |
25 | + public Long projectId; | |
26 | + public String projectName; | |
27 | + | |
28 | + public RecentProject(User user, Project project) { | |
29 | + userId = user.id; | |
30 | + this.owner = project.owner; | |
31 | + this.projectId = project.id; | |
32 | + this.projectName = project.name; | |
33 | + } | |
34 | + | |
35 | + @Transactional | |
36 | + public static List<Project> getRecentProjects(@Nonnull User user){ | |
37 | + List<RecentProject> recentProjects = find.where() | |
38 | + .eq("userId", user.id).findList(); | |
39 | + | |
40 | + List<Project> found = new ArrayList<>(); | |
41 | + | |
42 | + for(RecentProject rp: recentProjects){ | |
43 | + found.add(0, Project.findByOwnerAndProjectName(rp.owner, rp.projectName)); | |
44 | + } | |
45 | + | |
46 | + return found; | |
47 | + } | |
48 | + | |
49 | + @Transactional | |
50 | + public static void addNew(User user, Project project){ | |
51 | + try { | |
52 | + deletePrevious(user, project); | |
53 | + | |
54 | + RecentProject recentProject = new RecentProject(user, project); | |
55 | + recentProject.save(); | |
56 | + | |
57 | + deleteOldestIfOverflow(user); | |
58 | + } catch (OptimisticLockException ole){ | |
59 | + ole.printStackTrace(); | |
60 | + } | |
61 | + } | |
62 | + | |
63 | + private static void deletePrevious(User user, Project project) { | |
64 | + RecentProject existed = find.where() | |
65 | + .eq("userId", user.id) | |
66 | + .eq("projectId", project.id).findUnique(); | |
67 | + | |
68 | + if(existed != null){ | |
69 | + existed.delete(); | |
70 | + } | |
71 | + | |
72 | + } | |
73 | + | |
74 | + private static void deleteOldestIfOverflow(User user) { | |
75 | + List<RecentProject> recentProjects = find.where() | |
76 | + .eq("userId", user.id).findList(); | |
77 | + if(recentProjects.size() > MAX_RECENT_LIST_PER_USER){ | |
78 | + Comparator<RecentProject> comparator = new Comparator<RecentProject>() { | |
79 | + @Override | |
80 | + public int compare(RecentProject p1, RecentProject p2) { | |
81 | + return Long.compare( p1.id, p2.id); | |
82 | + } | |
83 | + }; | |
84 | + RecentProject oldest = Collections.min(recentProjects, comparator); | |
85 | + oldest.delete(); | |
86 | + } | |
87 | + } | |
88 | +} |
--- app/models/User.java
+++ app/models/User.java
... | ... | @@ -754,16 +754,16 @@ |
754 | 754 |
} |
755 | 755 |
|
756 | 756 |
public void visits(Project project) { |
757 |
- this.recentlyVisitedProjects = RecentlyVisitedProjects.addNewVisitation(this, project); |
|
758 |
- this.update(); |
|
757 |
+ RecentProject.addNew(this, project); |
|
759 | 758 |
} |
760 | 759 |
|
761 |
- public List<ProjectVisitation> getVisitedProjects(int size) { |
|
762 |
- if(size < 1 || this.recentlyVisitedProjects == null) { |
|
760 |
+ public List<Project> getVisitedProjects() { |
|
761 |
+ List<Project> projects = RecentProject.getRecentProjects(this); |
|
762 |
+ if(projects == null || projects.size() == 0){ |
|
763 | 763 |
return new ArrayList<>(); |
764 | 764 |
} |
765 | 765 |
|
766 |
- return this.recentlyVisitedProjects.findRecentlyVisitedProjects(size); |
|
766 |
+ return projects; |
|
767 | 767 |
} |
768 | 768 |
|
769 | 769 |
public List<Organization> getOrganizations(int size) { |
--- app/utils/Markdown.java
+++ app/utils/Markdown.java
... | ... | @@ -131,9 +131,9 @@ |
131 | 131 |
} |
132 | 132 |
|
133 | 133 |
private static String renderWithHighlight(String source, boolean breaks) { |
134 |
- if(CacheStore.renderedMarkdown.asMap().containsKey(source.hashCode())){ |
|
135 |
- return ZipUtil.decompress(CacheStore.renderedMarkdown.asMap().get(source.hashCode())); |
|
136 |
- } |
|
134 |
+// if(CacheStore.renderedMarkdown.asMap().containsKey(source.hashCode())){ |
|
135 |
+// return ZipUtil.decompress(CacheStore.renderedMarkdown.asMap().get(source.hashCode())); |
|
136 |
+// } |
|
137 | 137 |
try { |
138 | 138 |
Object options = engine.eval("new Object({gfm: true, tables: true, breaks: " + breaks + ", " + |
139 | 139 |
"pedantic: false, sanitize: false, smartLists: true," + |
... | ... | @@ -144,7 +144,7 @@ |
144 | 144 |
rendered = removeJavascriptInHref(rendered); |
145 | 145 |
rendered = checkReferrer(rendered); |
146 | 146 |
String sanitized = sanitize(rendered); |
147 |
- CacheStore.renderedMarkdown.asMap().putIfAbsent(source.hashCode(), ZipUtil.compress(sanitized)); |
|
147 |
+// CacheStore.renderedMarkdown.asMap().putIfAbsent(source.hashCode(), ZipUtil.compress(sanitized)); |
|
148 | 148 |
return sanitized; |
149 | 149 |
} catch (Exception ex) { |
150 | 150 |
throw new RuntimeException(ex); |
... | ... | @@ -190,14 +190,14 @@ |
190 | 190 |
} |
191 | 191 |
|
192 | 192 |
public static String render(@Nonnull String source) { |
193 |
- if(CacheStore.renderedMarkdown.asMap().containsKey(source.hashCode())){ |
|
194 |
- return ZipUtil.decompress(CacheStore.renderedMarkdown.asMap().get(source.hashCode())); |
|
195 |
- } |
|
193 |
+// if(CacheStore.renderedMarkdown.asMap().containsKey(source.hashCode())){ |
|
194 |
+// return ZipUtil.decompress(CacheStore.renderedMarkdown.asMap().get(source.hashCode())); |
|
195 |
+// } |
|
196 | 196 |
try { |
197 | 197 |
Object options = engine.eval("new Object({gfm: true, tables: true, breaks: true, " + |
198 | 198 |
"pedantic: false, sanitize: false, smartLists: true});"); |
199 | 199 |
String sanitized = sanitize(renderByMarked(source, options)); |
200 |
- CacheStore.renderedMarkdown.asMap().putIfAbsent(source.hashCode(), ZipUtil.compress(sanitized)); |
|
200 |
+// CacheStore.renderedMarkdown.asMap().putIfAbsent(source.hashCode(), ZipUtil.compress(sanitized)); |
|
201 | 201 |
return sanitized; |
202 | 202 |
} catch (Exception ex) { |
203 | 203 |
throw new RuntimeException(ex); |
--- app/views/index/myProjectList.scala.html
+++ app/views/index/myProjectList.scala.html
... | ... | @@ -34,14 +34,14 @@ |
34 | 34 |
} |
35 | 35 |
</ul> |
36 | 36 |
} |
37 |
-@defining(currentUser.getVisitedProjects(20)){ visitedProjects => |
|
37 |
+@defining(currentUser.getVisitedProjects){ visitedProjects => |
|
38 | 38 |
<ul class="tab-pane unstyled my-project-item active" id="recentlyVisited"> |
39 |
-@for(visited <- visitedProjects){ |
|
40 |
- <li class="my-list-item" data-item="my-item" data-value="@if(visited.project.owner != currentUser.loginId) {@visited.project.owner / }@visited.project.name"> |
|
41 |
- @if(hasProjectLogo(visited.project)){<img src="@urlToProjectLogo(visited.project)" alt="@visited.project.name"/>} else{<span class="dummy-25px"> </span>}<a href="@routes.ProjectApp.project(visited.project.owner, visited.project.name)" class="project-name"> |
|
42 |
- <strong>@visited.project.name @if(visited.project.isPrivate){ <i class="yobicon-lock yobicon-small"></i> }</strong> |
|
39 |
+@for(project <- visitedProjects){ |
|
40 |
+ <li class="my-list-item" data-item="my-item" data-value="@if(project.owner != currentUser.loginId) {@project.owner / }@project.name"> |
|
41 |
+ @if(hasProjectLogo(project)){<img src="@urlToProjectLogo(project)" alt="@project.name"/>} else{<span class="dummy-25px"> </span>}<a href="@routes.ProjectApp.project(project.owner, project.name)" class="project-name"> |
|
42 |
+ <strong>@project.name @if(project.isPrivate){ <i class="yobicon-lock yobicon-small"></i> }</strong> |
|
43 | 43 |
</a> |
44 |
- <span class="gray-txt small-font">of <a href="@routes.UserApp.userInfo(visited.project.owner)" >@visited.project.owner</a></span> |
|
44 |
+ <span class="gray-txt small-font">of <a href="@routes.UserApp.userInfo(project.owner)" >@project.owner</a></span> |
|
45 | 45 |
</li> |
46 | 46 |
} |
47 | 47 |
</ul> |
+++ conf/evolutions/default/4.sql
... | ... | @@ -0,0 +1,17 @@ |
1 | +# --- !Ups | |
2 | + | |
3 | +create table recent_project ( | |
4 | + id bigint auto_increment not null, | |
5 | + user_id bigint, | |
6 | + owner varchar(255), | |
7 | + project_id bigint, | |
8 | + project_name varchar(255), | |
9 | + constraint pk_recent_project primary key (id), | |
10 | + constraint uq_recent_project_1 unique (user_id, project_id)) | |
11 | + row_format=compressed, key_block_size=8 | |
12 | +; | |
13 | + | |
14 | +alter table recent_project add constraint fk_recent_project_project_2 foreign key (project_id) references project (id) on delete CASCADE on update CASCADE; | |
15 | + | |
16 | +# --- !Downs | |
17 | +drop table recent_project; |
--- test/models/RecentlyVisitedProjectsTest.java
+++ test/models/RecentlyVisitedProjectsTest.java
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 |
|
23 | 23 |
import org.junit.After; |
24 | 24 |
import org.junit.Before; |
25 |
+import org.junit.Ignore; |
|
25 | 26 |
import org.junit.Test; |
26 | 27 |
|
27 | 28 |
import java.util.List; |
... | ... | @@ -31,6 +32,7 @@ |
31 | 32 |
/** |
32 | 33 |
* @author Keeun Baik |
33 | 34 |
*/ |
35 |
+@Ignore |
|
34 | 36 |
public class RecentlyVisitedProjectsTest extends ModelTest<RecentlyVisitedProjects> { |
35 | 37 |
|
36 | 38 |
User doortts; |
... | ... | @@ -117,7 +119,7 @@ |
117 | 119 |
doortts.visits(cubrid); |
118 | 120 |
|
119 | 121 |
// When |
120 |
- List<ProjectVisitation> projects = doortts.getVisitedProjects(2); |
|
122 |
+ List<ProjectVisitation> projects = doortts.getVisitedProjects(); |
|
121 | 123 |
|
122 | 124 |
// Then |
123 | 125 |
assertThat(projects.size()).isEqualTo(2); |
... | ... | @@ -135,7 +137,7 @@ |
135 | 137 |
doortts.visits(yobi); |
136 | 138 |
|
137 | 139 |
// When |
138 |
- List<ProjectVisitation> projects = doortts.getVisitedProjects(2); |
|
140 |
+ List<ProjectVisitation> projects = doortts.getVisitedProjects(); |
|
139 | 141 |
|
140 | 142 |
// Then |
141 | 143 |
assertThat(projects.size()).isEqualTo(2); |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?