-
Notifications
You must be signed in to change notification settings - Fork 0
Implement SQL Repos #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| package org.patinanetwork.patchats.api.match.db.repos; | ||
|
|
||
| import java.sql.ResultSet; | ||
| import java.sql.SQLException; | ||
| import java.time.Instant; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.patinanetwork.patchats.api.match.db.models.MatchCycle; | ||
| import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; | ||
| import org.springframework.jdbc.core.simple.JdbcClient; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| @Repository | ||
| @RequiredArgsConstructor | ||
| public class MatchCycleSqlRepo implements MatchCycleRepo { | ||
| private final JdbcClient jdbc; | ||
|
|
||
| private MatchCycle parseResultSetToMatchCycle(final ResultSet rs) throws SQLException { | ||
| return MatchCycle.builder() | ||
| .id(rs.getInt("id")) | ||
| .period(rs.getString("period")) | ||
|
Check failure on line 22 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchCycleSqlRepo.java
|
||
| .runAt(rs.getObject("run_at", Instant.class)) | ||
|
Check failure on line 23 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchCycleSqlRepo.java
|
||
| .totalMembers(rs.getInt("total_members")) | ||
|
Check failure on line 24 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchCycleSqlRepo.java
|
||
| .totalMatched(rs.getInt("total_matched")) | ||
|
Check failure on line 25 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchCycleSqlRepo.java
|
||
| .build(); | ||
| } | ||
|
|
||
| @Override | ||
| public MatchCycle createMatchCycle(MatchCycle matchCycle) { | ||
| String sql = """ | ||
| INSERT INTO "match_cycles" ( | ||
| "period", | ||
| "run_at", | ||
| "total_members", | ||
| "total_matched" | ||
| ) | ||
| VALUES( | ||
| :period, | ||
| :run_at, | ||
| :total_members, | ||
| :total_matched | ||
| ) | ||
| RETURNING | ||
| * | ||
| """; | ||
|
|
||
| return jdbc.sql(sql) | ||
| .param("period", matchCycle.getPeriod()) | ||
| .param("run_at", matchCycle.getRunAt()) | ||
| .param("total_members", matchCycle.getTotalMembers()) | ||
| .param("total_matched", matchCycle.getTotalMatched()) | ||
| .query((rs, rowNum) -> parseResultSetToMatchCycle(rs)) | ||
| .single(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<MatchCycle> updateMatchCycle(MatchCycle matchCycle) { | ||
| String sql = """ | ||
| UPDATE "match_cycles" SET | ||
| "period" = :period, | ||
| "run_at" = :run_at, | ||
| "total_members" = :total_members, | ||
| "total_matched" = :total_matched | ||
| WHERE "id" = :id | ||
| RETURNING * | ||
| """; | ||
|
|
||
| return jdbc.sql(sql) | ||
| .param("id", matchCycle.getId()) | ||
| .param("period", matchCycle.getPeriod()) | ||
| .param("run_at", matchCycle.getRunAt()) | ||
| .param("total_members", matchCycle.getTotalMembers()) | ||
| .param("total_matched", matchCycle.getTotalMatched()) | ||
| .query((rs, rowNum) -> parseResultSetToMatchCycle(rs)) | ||
| .optional(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<MatchCycle> getMatchCycleById(Integer id) { | ||
| String sql = "SELECT * FROM match_cycles WHERE id = :id"; | ||
| return jdbc.sql(sql) | ||
| .param("id", id) | ||
| .query((rs, rowNum) -> parseResultSetToMatchCycle(rs)) | ||
| .optional(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<MatchCycle> deleteMatchCycleById(Integer id) { | ||
| String sql = "DELETE FROM match_cycles WHERE id = :id RETURNING *"; | ||
| return jdbc.sql(sql) | ||
| .param("id", id) | ||
| .query((rs, rowNum) -> parseResultSetToMatchCycle(rs)) | ||
| .optional(); | ||
| } | ||
|
|
||
| @Override | ||
| public List<MatchCycle> filterMatchCycles(MatchCycleFilterCriteria criteria) { | ||
| StringBuilder sql = new StringBuilder("SELECT * FROM match_cycles WHERE 1=1"); | ||
| MapSqlParameterSource params = new MapSqlParameterSource(); | ||
|
|
||
| criteria.period().ifPresent(period -> { | ||
| sql.append(" AND period = :period"); | ||
| params.addValue("period", period); | ||
| }); | ||
|
|
||
| criteria.startTime().ifPresent(start -> { | ||
| sql.append(" AND run_at >= :start_time"); | ||
| params.addValue("start_time", start); | ||
| }); | ||
|
|
||
| criteria.endTime().ifPresent(end -> { | ||
| sql.append(" AND run_at <= :end_time"); | ||
| params.addValue("end_time", end); | ||
| }); | ||
|
|
||
| return jdbc.sql(sql.toString()) | ||
| .paramSource(params) | ||
| .query((rs, rowNum) -> parseResultSetToMatchCycle(rs)) | ||
| .list(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,198 @@ | ||
| package org.patinanetwork.patchats.api.match.db.repos; | ||
|
|
||
| import java.sql.ResultSet; | ||
| import java.sql.SQLException; | ||
| import java.time.Instant; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
| import java.util.UUID; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.patinanetwork.patchats.api.match.db.models.Match; | ||
| import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; | ||
| import org.springframework.jdbc.core.simple.JdbcClient; | ||
| import org.springframework.stereotype.Repository; | ||
|
|
||
| @Repository | ||
| @RequiredArgsConstructor | ||
| public class MatchSqlRepo implements MatchRepo { | ||
| private final JdbcClient jdbc; | ||
|
|
||
| private Match parseResultSetToMatch(final ResultSet rs) throws SQLException { | ||
| return Match.builder() | ||
| .id(UUID.fromString(rs.getString("id"))) | ||
| .memberAId(UUID.fromString(rs.getString("member_a_id"))) | ||
|
Check failure on line 23 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchSqlRepo.java
|
||
| .memberBId(UUID.fromString(rs.getString("member_b_id"))) | ||
|
Check failure on line 24 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchSqlRepo.java
|
||
| .matchCycleId(rs.getInt("cycle_id")) | ||
|
Check failure on line 25 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchSqlRepo.java
|
||
| .matchScore(rs.getObject("match_score", Double.class)) | ||
|
Check failure on line 26 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchSqlRepo.java
|
||
| .status(rs.getString("status")) | ||
|
Check failure on line 27 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchSqlRepo.java
|
||
| .feedbackA(rs.getString("feedback_a")) | ||
|
Check failure on line 28 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchSqlRepo.java
|
||
| .feedbackB(rs.getString("feedback_b")) | ||
|
Check failure on line 29 in src/main/java/org/patinanetwork/patchats/api/match/db/repos/MatchSqlRepo.java
|
||
| .createdAt(rs.getObject("created_at", Instant.class)) | ||
| .build(); | ||
| } | ||
|
|
||
| @Override | ||
| public Match createMatch(Match match) { | ||
| String sql = """ | ||
| INSERT INTO "matches" ( | ||
| "id", | ||
| "member_a_id", | ||
| "member_b_id", | ||
| "cycle_id", | ||
| "match_score", | ||
| "status", | ||
| "feedback_a", | ||
| "feedback_b" | ||
| ) | ||
| VALUES( | ||
| :id, | ||
| :member_a_id, | ||
| :member_b_id, | ||
| :cycle_id, | ||
| :match_score, | ||
| :status, | ||
| :feedback_a, | ||
| :feedback_b | ||
| ) | ||
| RETURNING | ||
| * | ||
| """; | ||
| return jdbc.sql(sql) | ||
| .param("id", match.getId()) | ||
| .param("member_a_id", match.getMemberAId()) | ||
| .param("member_b_id", match.getMemberBId()) | ||
| .param("cycle_id", match.getMatchCycleId()) | ||
| .param("match_score", match.getMatchScore()) | ||
| .param("status", match.getStatus()) | ||
| .param("feedback_a", match.getFeedbackA()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd actually remove feedback from this table as well, and make a table for feedback specifically. It'd be: feedback content could be like 1-5 stars, text field for written things or whatever else we think of. But that leaves it to be a lot more flexible. |
||
| .param("feedback_b", match.getFeedbackB()) | ||
| .query((rs, rowNum) -> parseResultSetToMatch(rs)) | ||
| .single(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<Match> updateMatch(Match match) { | ||
| String sql = """ | ||
| UPDATE "matches" SET | ||
| "member_a_id" = :member_a_id, | ||
| "member_b_id" = :member_b_id, | ||
| "cycle_id" = :cycle_id, | ||
| "match_score" = :match_score, | ||
| "status" = :status, | ||
| "feedback_a" = :feedback_a, | ||
| "feedback_b" = :feedback_b | ||
| WHERE "id" = :id | ||
| RETURNING * | ||
| """; | ||
| return jdbc.sql(sql) | ||
| .param("id", match.getId()) | ||
| .param("member_a_id", match.getMemberAId()) | ||
| .param("member_b_id", match.getMemberBId()) | ||
| .param("cycle_id", match.getMatchCycleId()) | ||
| .param("match_score", match.getMatchScore()) | ||
| .param("status", match.getStatus()) | ||
| .param("feedback_a", match.getFeedbackA()) | ||
| .param("feedback_b", match.getFeedbackB()) | ||
| .query((rs, rowNum) -> parseResultSetToMatch(rs)) | ||
| .optional(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<Match> getMatchById(UUID id) { | ||
| String sql = "SELECT * FROM matches WHERE id = :id"; | ||
|
rootandroo marked this conversation as resolved.
|
||
| return jdbc.sql(sql) | ||
| .param("id", id) | ||
| .query((rs, rowNum) -> parseResultSetToMatch(rs)) | ||
| .optional(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<Match> setMatchStatus(UUID id, String status) { | ||
| String sql = """ | ||
| UPDATE "matches" SET "status" = :status | ||
| WHERE "id" = :id | ||
| RETURNING * | ||
| """; | ||
| return jdbc.sql(sql) | ||
| .param("id", id) | ||
| .param("status", status) | ||
| .query((rs, rowNum) -> parseResultSetToMatch(rs)) | ||
| .optional(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<Match> deleteMatchById(UUID id) { | ||
| String sql = "DELETE FROM matches WHERE id = :id RETURNING *"; | ||
| return jdbc.sql(sql) | ||
| .param("id", id) | ||
| .query((rs, rowNum) -> parseResultSetToMatch(rs)) | ||
| .optional(); | ||
| } | ||
|
|
||
| @Override | ||
| public Optional<Match> recordFeedback(UUID id, UUID memberId, String feedback) { | ||
| String sql = """ | ||
| UPDATE "matches" SET | ||
| "feedback_a" = CASE WHEN "member_a_id" = :member_id THEN :feedback ELSE "feedback_a" END, | ||
| "feedback_b" = CASE WHEN "member_b_id" = :member_id THEN :feedback ELSE "feedback_b" END | ||
| WHERE "id" = :id AND ("member_a_id" = :member_id OR "member_b_id" = :member_id) | ||
| RETURNING * | ||
| """; | ||
| return jdbc.sql(sql) | ||
| .param("id", id) | ||
| .param("member_id", memberId) | ||
| .param("feedback", feedback) | ||
| .query((rs, rowNum) -> parseResultSetToMatch(rs)) | ||
| .optional(); | ||
| } | ||
|
|
||
| @Override | ||
| public List<Match> filterMatches(MatchFilterCriteria criteria) { | ||
| StringBuilder sql = new StringBuilder("SELECT * FROM matches WHERE 1=1"); | ||
| MapSqlParameterSource params = new MapSqlParameterSource(); | ||
|
|
||
| criteria.status().ifPresent(status -> { | ||
| sql.append(" AND status = :status"); | ||
| params.addValue("status", status); | ||
| }); | ||
|
|
||
| criteria.memberId().ifPresent(memberId -> { | ||
| sql.append(" AND (member_a_id = :member_id OR member_b_id = :member_id)"); | ||
| params.addValue("member_id", memberId); | ||
| }); | ||
|
|
||
| criteria.matchCycleId().ifPresent(cycleId -> { | ||
| sql.append(" AND cycle_id = :cycle_id"); | ||
| params.addValue("cycle_id", cycleId); | ||
| }); | ||
|
|
||
| criteria.startTime().ifPresent(start -> { | ||
| sql.append(" AND created_at >= :start_time"); | ||
| params.addValue("start_time", start); | ||
| }); | ||
|
|
||
| criteria.endTime().ifPresent(end -> { | ||
| sql.append(" AND created_at <= :end_time"); | ||
| params.addValue("end_time", end); | ||
| }); | ||
|
|
||
| criteria.period().ifPresent(period -> { | ||
| sql.append(" AND cycle_id IN (SELECT id FROM match_cycles WHERE period = :period)"); | ||
| params.addValue("period", period); | ||
| }); | ||
|
|
||
| criteria.memberIndustry().ifPresent(memberIndustry -> { | ||
| sql.append(" AND ("); | ||
| sql.append("member_a_id IN (SELECT id FROM members WHERE industry_pref = :member_industry)"); | ||
| sql.append(" OR "); | ||
| sql.append("member_b_id IN (SELECT id FROM members WHERE industry_pref = :member_industry)"); | ||
| sql.append(")"); | ||
| params.addValue("member_industry", memberIndustry); | ||
| }); | ||
|
rootandroo marked this conversation as resolved.
|
||
|
|
||
| return jdbc.sql(sql.toString()) | ||
| .paramSource(params) | ||
| .query((rs, rowNum) -> parseResultSetToMatch(rs)) | ||
| .list(); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, we can calculate this by looking at the match table and then counting the rows right?
One issue with this is that if we have a new pending MatchCycle, then the count could be changing as we add more matches. So then we would have to update this sychronously with adding matches to the match table. Having the same information in two different places is a huge pain to keep synced.
Potentially we can fill these numbers in when we change a MatchCycle from pending to live, so that they're cached, so we don't have to compute them each time. If it's not like read only though, it would still require syncing tho. Like if we edit matches after it goes live.
We should also make a new column for the table that is like: isLive, which we flip when we go send the emails out.