Skip to content

Commit

Permalink
Merge pull request #64 from FortnoxAB/question-sorting
Browse files Browse the repository at this point in the history
Improved sorting of latest questions
  • Loading branch information
kindanice authored Aug 26, 2019
2 parents 4a282d2 + dbcc5b2 commit f116157
Show file tree
Hide file tree
Showing 25 changed files with 818 additions and 183 deletions.
2 changes: 1 addition & 1 deletion CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @FortnoxAB/rocket-fuelers
* @FortnoxAB/rocket-fuelers
2 changes: 0 additions & 2 deletions api/src/main/java/api/Answer.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package api;

import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Objects;

import static java.util.Objects.nonNull;

Expand Down
7 changes: 4 additions & 3 deletions api/src/main/java/api/Post.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package api;

import java.time.LocalDateTime;

/**
* A class that defines the shared attributes between a {@link Answer}
Expand All @@ -14,7 +15,7 @@ public abstract class Post {

private String picture;

private String createdAt;
private LocalDateTime createdAt;

private Integer votes;

Expand All @@ -30,11 +31,11 @@ public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}

public String getCreatedAt() {
public LocalDateTime getCreatedAt() {
return createdAt;
}

public void setCreatedAt(String createdAt) {
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}

Expand Down
41 changes: 36 additions & 5 deletions api/src/main/java/api/QuestionResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import api.auth.Auth;
import rx.Observable;
import se.fortnox.reactivewizard.CollectionOptions;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
Expand Down Expand Up @@ -33,14 +34,44 @@ public interface QuestionResource {
Observable<Question> getQuestion(Auth auth, @PathParam("questionId") long questionId);

/**
* Return a list of latest questions with a limit
* Return a list of latest questions
*
* @param limit
* @param options Sorting and limiting options
* @return questions
*/
@GET
@Path("questions/latest")
Observable<List<Question>> getLatestQuestion(@QueryParam("limit") Integer limit);
Observable<List<Question>> getLatestQuestions(CollectionOptions options);

/**
* Return a list of the highest voted questions
*
* @param options Sorting and limiting options
* @return questions
*/
@GET
@Path("questions/popular")
Observable<List<Question>> getPopularQuestions(CollectionOptions options);

/**
* Return a list of the highest voted questions without any answers
*
* @param options Sorting and limiting options
* @return questions
*/
@GET
@Path("questions/popularunanswered")
Observable<List<Question>> getPopularUnansweredQuestions(CollectionOptions options);

/**
* Return a list of the questions that had an answer accepted the most recently
*
* @param options Sorting and limiting options
* @return questions
*/
@GET
@Path("questions/recentlyaccepted")
Observable<List<Question>> getRecentlyAcceptedQuestions(CollectionOptions options);

/**
* Adds a question and links it to the given userId.
Expand All @@ -54,15 +85,15 @@ public interface QuestionResource {
*/
@GET
@Path("questions")
Observable<List<Question>> getQuestionsBySearchQuery(@QueryParam("search") String searchQuery, @QueryParam("limit") Integer limit);
Observable<List<Question>> getQuestionsBySearchQuery(@QueryParam("search") String searchQuery, CollectionOptions options);


/**
* Returns all questions for a given user
*/
@Path("users/{userId}/questions")
@GET
Observable<List<Question>> getQuestions(@PathParam("userId") long userId);
Observable<List<Question>> getQuestions(@PathParam("userId") long userId, CollectionOptions options);

/**
* Updates the question with the given questionId
Expand Down
129 changes: 107 additions & 22 deletions impl/src/main/java/dao/QuestionDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,149 @@

import api.Question;
import rx.Observable;
import se.fortnox.reactivewizard.CollectionOptions;
import se.fortnox.reactivewizard.db.GeneratedKey;
import se.fortnox.reactivewizard.db.Query;
import se.fortnox.reactivewizard.db.Update;

import java.time.LocalDateTime;

public interface QuestionDao {

@Query(
value =
"SELECT " +
"question.id, " +
"question.question, " +
"answer_accepted, " +
"question.title, " +
"question.bounty, " +
"question.votes, " +
"question.created_at, " +
"question,user_id, " +
"question.user_id, " +
"question.slack_id, \"user\".picture, \"user\".name as created_by, " +
"(SELECT COALESCE(SUM(question_vote.value), 0) FROM question_vote WHERE question_vote.question_id = question.id) AS votes " +
"FROM " +
"question " +
"INNER JOIN " +
"\"user\" on \"user\".id = question.user_id WHERE question.user_id=:userId")
Observable<Question> getQuestions(long userId);
"\"user\" on \"user\".id = question.user_id WHERE question.user_id=:userId " +
"ORDER BY " +
"question.created_at DESC ",
defaultLimit = 10,
maxLimit = 50)
Observable<Question> getQuestions(long userId, CollectionOptions options);

@Query(
value =
"SELECT " +
"question.id, " +
"question.question, " +
"answer_accepted, " +
"question.title, " +
"question.bounty, " +
"question.votes, " +
"question.created_at, " +
"question,user_id, " +
"question.user_id, " +
"question.slack_id, " +
"\"user\".picture, \"user\".name as created_by, " +
"\"user\".picture, " +
"\"user\".name as created_by, " +
"(SELECT COALESCE(SUM(question_vote.value), 0) FROM question_vote WHERE question_vote.question_id = question.id) AS votes " +
"FROM " +
"question " +
"INNER JOIN " +
"\"user\" on \"user\".id = question.user_id " +
"ORDER BY " +
"question.created_at DESC " +
"LIMIT " +
":limit")
Observable<Question> getLatestQuestions(Integer limit);
"question.created_at DESC ",
defaultLimit = 10,
maxLimit = 50)
Observable<Question> getLatestQuestions(CollectionOptions options);

@Query(
value =
"SELECT " +
"question.id, " +
"question.question, " +
"answer_accepted, " +
"question.title, " +
"question.bounty, " +
"question.created_at, " +
"question.user_id, " +
"question.slack_id, " +
"\"user\".picture, " +
"\"user\".name as created_by, " +
"(SELECT COALESCE(SUM(question_vote.value), 0) FROM question_vote WHERE question_vote.question_id = question.id) AS votes " +
"FROM " +
"question " +
"INNER JOIN " +
"\"user\" on \"user\".id = question.user_id " +
"ORDER BY " +
"votes DESC NULLS LAST, " +
"question.created_at DESC ",
defaultLimit = 10,
maxLimit = 50)
Observable<Question> getPopularQuestions(CollectionOptions options);

@Query(
value =
"SELECT " +
"question.id, " +
"question.question, " +
"answer_accepted, " +
"question.title, " +
"question.bounty, " +
"question.created_at, " +
"question.user_id, " +
"question.slack_id, " +
"\"user\".picture, " +
"\"user\".name as created_by, " +
"(SELECT COALESCE(SUM(question_vote.value), 0) FROM question_vote WHERE question_vote.question_id = question.id) AS votes " +
"FROM " +
"question " +
"INNER JOIN " +
"\"user\" on \"user\".id = question.user_id " +
"LEFT JOIN " +
"answer on answer.question_id = question.id " +
"WHERE " +
"answer IS NULL " +
"ORDER BY " +
"votes DESC NULLS LAST, " +
"question.created_at DESC ",
defaultLimit = 10,
maxLimit = 50)
Observable<Question> getPopularUnansweredQuestions(CollectionOptions options);

@Query(
value =
"SELECT " +
"question.id, " +
"question.question, " +
"answer_accepted, " +
"question.title, " +
"question.bounty, " +
"question.created_at, " +
"question.user_id, " +
"question.slack_id, " +
"\"user\".picture, " +
"\"user\".name as created_by, " +
"(SELECT COALESCE(SUM(question_vote.value), 0) FROM question_vote WHERE question_vote.question_id = question.id) AS votes " +
"FROM " +
"question " +
"INNER JOIN " +
"\"user\" on \"user\".id = question.user_id " +
"LEFT JOIN " +
"answer on answer.question_id = question.id " +
"WHERE " +
"answer.accepted_at IS NOT NULL " +
"ORDER BY " +
"answer.accepted_at DESC NULLS LAST ",
defaultLimit = 10,
maxLimit = 50)
Observable<Question> getRecentlyAcceptedQuestions(CollectionOptions options);

@Update(
"INSERT INTO " +
"question (" +
"question, " +
"title, " +
"bounty, " +
"votes, " +
"created_at, " +
"user_id, " +
"slack_id) " +
Expand All @@ -64,7 +153,6 @@ public interface QuestionDao {
":question.question, " +
":question.title, " +
":question.bounty, " +
"0, " +
"NOW(), " +
":userId, " +
":question.slackId" +
Expand All @@ -82,7 +170,6 @@ public interface QuestionDao {
"question, " +
"title, " +
"bounty, " +
"votes, " +
"answer_accepted, " +
"created_at, " +
"\"user\".name as created_by, " +
Expand All @@ -107,7 +194,6 @@ public interface QuestionDao {
"question, " +
"title, " +
"bounty, " +
"votes, " +
"answer_accepted, " +
"created_at, " +
"user_id, " +
Expand Down Expand Up @@ -137,7 +223,6 @@ public interface QuestionDao {
"SELECT " +
"id, question, " +
"title, bounty, " +
"votes, " +
"answer_accepted, " +
"created_at, user_id, " +
"slack_id, " +
Expand All @@ -155,13 +240,13 @@ public interface QuestionDao {
Observable<Void> deleteQuestion(long userId, long questionId);

@Query(
value =
"SELECT DISTINCT " +
"question.id, " +
"question.question, " +
"answer_accepted, " +
"question.title, " +
"question.bounty, " +
"question.votes, " +
"question.created_at, " +
"question, " +
"question.user_id, " +
Expand All @@ -180,9 +265,9 @@ public interface QuestionDao {
"OR " +
"answer.answer ILIKE ('%' || :search || '%') " +
"ORDER BY " +
"question.votes desc, " +
"question.created_at desc " +
"LIMIT " +
":limit")
Observable<Question> getQuestions(String search, Integer limit);
"votes desc, " +
"question.created_at desc ",
defaultLimit = 50,
maxLimit = 50)
Observable<Question> getQuestions(String search, CollectionOptions options);
}
35 changes: 35 additions & 0 deletions impl/src/main/java/dates/RWDateFormat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package dates;

import com.fasterxml.jackson.databind.util.StdDateFormat;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
* Workaround for framework bug. Should be removed once fixed.
*/
public class RWDateFormat extends StdDateFormat {

public RWDateFormat() {
super(TimeZone.getDefault(), Locale.getDefault(), true);
}

@Override
public Date parse(String dateStr) throws ParseException {
try {
return super.parse(dateStr);
} catch (ParseException e) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
fmt.setTimeZone(TimeZone.getDefault());
return fmt.parse(dateStr);
}
}

@Override
public StdDateFormat clone() {
return new RWDateFormat();
}
}
Loading

0 comments on commit f116157

Please sign in to comment.