-
Notifications
You must be signed in to change notification settings - Fork 0
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
Feature/hodadako step2 #10
base: hodadako
Are you sure you want to change the base?
Changes from all commits
8f54171
f089469
cdaa674
1218dd7
86663df
706ca99
859b1cf
f3d8a77
d068b63
5b1bdd6
247f630
e7e28b0
cd2bba5
6e69f79
0c95cb2
62f666b
b1835c2
ae2ce83
1df5d6f
cac2551
d6bed25
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,69 @@ | ||
package org.c4marathon.assignment.domain.transaction.entity; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.Objects; | ||
|
||
import org.c4marathon.assignment.common.entity.BaseEntity; | ||
import org.hibernate.annotations.ColumnDefault; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Table; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Table(name = "transaction", indexes = {}) | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class Transaction { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "transaction_id") // 여기서 컬럼명을 "transaction_id"로 변경 | ||
private Integer id; | ||
|
||
@Column(name = "sender_account", columnDefinition = "varchar(20)", nullable = false) | ||
private String senderAccount; | ||
|
||
@Column(name = "receiver_account", columnDefinition = "varchar(20)", nullable = false) | ||
private String receiverAccount; | ||
|
||
@Column(name = "sender_swift_code", columnDefinition = "varchar(11)", nullable = false) | ||
private String senderSwiftCode; | ||
|
||
@Column(name = "receiver_swift_code", columnDefinition = "varchar(11)", nullable = false) | ||
private String receiverSwiftCode; | ||
|
||
@Column(name = "sender_name", columnDefinition = "varchar(30)", nullable = false) | ||
private String senderName; | ||
|
||
@Column(name = "receiver_name", columnDefinition = "varchar(30)", nullable = false) | ||
private String receiverName; | ||
|
||
@Column(name = "amount", nullable = false) | ||
private Long amount; | ||
|
||
@Column(name = "memo", columnDefinition = "varchar(200)") | ||
private String memo; | ||
|
||
@ColumnDefault("CURRENT_TIMESTAMP") | ||
@Column(name = "transaction_date", nullable = false) | ||
private LocalDateTime transactionDate; | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (o instanceof Transaction t) { | ||
return this.getId() == t.getId(); | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(this); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package org.c4marathon.assignment.domain.transaction.entity; | ||
|
||
public enum TransactionType { | ||
TRANSFER | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.c4marathon.assignment.domain.transaction.repository; | ||
|
||
import java.time.LocalDate; | ||
import java.util.stream.Stream; | ||
|
||
import org.c4marathon.assignment.domain.transfer_statistics.entity.TransferStatistics; | ||
import org.springframework.stereotype.Component; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class TransactionReader { | ||
private final TransactionRepository transactionRepository; | ||
|
||
public Stream<TransferStatistics> findTransferStatisticsBetweeen(LocalDate from, LocalDate to) { | ||
return transactionRepository.findTransactionBetween(from, to); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package org.c4marathon.assignment.domain.transaction.repository; | ||
|
||
import java.time.LocalDate; | ||
import java.util.stream.Stream; | ||
|
||
import org.c4marathon.assignment.domain.transaction.entity.Transaction; | ||
import org.c4marathon.assignment.domain.transfer_statistics.entity.TransferStatistics; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.data.repository.query.Param; | ||
|
||
public interface TransactionRepository extends JpaRepository<Transaction, Long> { | ||
@Query( | ||
""" | ||
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. 혹시 해당 쿼리의 실행계획을 확인하셨을까요? |
||
SELECT new TransferStatistics(SUM(t.amount), | ||
SUM(SUM(t.amount)) OVER (ORDER BY DATE(t.transactionDate)), t.transactionDate) | ||
FROM Transaction t | ||
WHERE t.transactionDate BETWEEN :startDate AND :endDate | ||
GROUP BY t.transactionDate | ||
ORDER BY t.transactionDate DESC | ||
""") | ||
Stream<TransferStatistics> findTransactionBetween(@Param("startDate") LocalDate startDate, | ||
@Param("endDate") LocalDate endDate); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.c4marathon.assignment.domain.transfer_statistics.dto; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.PastOrPresent; | ||
|
||
public record AggregateTransferStatisticsRequest( | ||
@NotBlank | ||
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.
|
||
@PastOrPresent | ||
LocalDateTime targetDate | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package org.c4marathon.assignment.domain.transfer_statistics.dto; | ||
|
||
import java.time.LocalDate; | ||
|
||
import jakarta.validation.constraints.AssertTrue; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.Past; | ||
|
||
public record GetAllTransferStatisticsRequest( | ||
@NotBlank | ||
@Past | ||
LocalDate startDate, | ||
@NotBlank | ||
@Past | ||
LocalDate endDate | ||
) { | ||
@AssertTrue(message = "시작 날짜는 종료 날짜보다 이전이어야 합니다.") | ||
public boolean isStartDateBeforeEndDate() { | ||
return startDate.isBefore(endDate); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package org.c4marathon.assignment.domain.transfer_statistics.entity; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.Objects; | ||
|
||
import org.c4marathon.assignment.common.entity.BaseEntity; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.Table; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Table(name = "transfer_statistics_hodadako") | ||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class TransferStatistics extends BaseEntity { | ||
@Column(name = "daily_total_amount", columnDefinition = "bigint") | ||
private Long dailyTotalAmount; | ||
|
||
@Column(name = "cumulative_total_amount", columnDefinition = "bigint") | ||
private Long cumulativeTotalAmount; | ||
|
||
@Column(name = "unit_date", columnDefinition = "datetime") | ||
private LocalDateTime unitDate; | ||
|
||
public TransferStatistics(Long dailyTotalAmount, Long cumulativeTotalAmount, LocalDateTime unitDate) { | ||
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.
|
||
this.dailyTotalAmount = dailyTotalAmount; | ||
this.cumulativeTotalAmount = cumulativeTotalAmount; | ||
this.unitDate = unitDate; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (o instanceof TransferStatistics transferStatistics) { | ||
return this.getId() == transferStatistics.getId(); | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(this); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package org.c4marathon.assignment.domain.transfer_statistics.presentation; | ||
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. 일반적으로 패키지명에 underscore를 삽입하는 것은 매우 권장되지 않습니다. (ex1. https://google.github.io/styleguide/javaguide.html#s5.2.1-package-names) |
||
|
||
import java.time.LocalDate; | ||
import java.util.List; | ||
|
||
import org.c4marathon.assignment.domain.transfer_statistics.dto.AggregateTransferStatisticsRequest; | ||
import org.c4marathon.assignment.domain.transfer_statistics.dto.GetAllTransferStatisticsRequest; | ||
import org.c4marathon.assignment.domain.transfer_statistics.entity.TransferStatistics; | ||
import org.c4marathon.assignment.domain.transfer_statistics.service.TransferStatisticsService; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api") | ||
public class TransferStatisticsController { | ||
private final TransferStatisticsService transferStatisticsService; | ||
|
||
@GetMapping("/v1/transfer-statistics") | ||
public ResponseEntity<List<TransferStatistics>> getTransferStatisticsInBetween( | ||
@RequestParam(name = "start-date") LocalDate startDate, @RequestParam(name = "end-date") LocalDate endDate) { | ||
return ResponseEntity.ok( | ||
transferStatisticsService.findAllByUnitDateBetween( | ||
new GetAllTransferStatisticsRequest(startDate, endDate))); | ||
} | ||
|
||
@PostMapping("/v1/transfer-statistics") | ||
public ResponseEntity<TransferStatistics> aggregateTransferStatistics( | ||
@RequestBody AggregateTransferStatisticsRequest request | ||
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. Request 객체에 Validation 어노테이션을 박았지만, 막상 여기서 |
||
) { | ||
return ResponseEntity.ok(transferStatisticsService.getStatistics(request)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package org.c4marathon.assignment.domain.transfer_statistics.repository; | ||
|
||
import java.time.LocalDate; | ||
import java.util.stream.Stream; | ||
|
||
import org.c4marathon.assignment.domain.transfer_statistics.entity.TransferStatistics; | ||
import org.springframework.stereotype.Component; | ||
|
||
import jakarta.persistence.EntityNotFoundException; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class TransferStatisticsReader { | ||
private final TransferStatisticsRepository transferStatisticsRepository; | ||
|
||
public Stream<TransferStatistics> findAllByUnitDateBetween(LocalDate from, LocalDate to) { | ||
return transferStatisticsRepository.findAllByUnitDateBetween(from, to); | ||
} | ||
|
||
public TransferStatistics findByUnitDate(LocalDate date) { | ||
return transferStatisticsRepository.findByUnitDate(date) | ||
.orElseThrow(() -> new EntityNotFoundException("해당 송금 통계는 존재하지 않습니다.")); | ||
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. 해당 에러가 HTTP 500을 반환해야 하나요? |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package org.c4marathon.assignment.domain.transfer_statistics.repository; | ||
|
||
import static org.hibernate.jpa.HibernateHints.*; | ||
|
||
import java.time.LocalDate; | ||
import java.util.Optional; | ||
import java.util.stream.Stream; | ||
|
||
import org.c4marathon.assignment.domain.transfer_statistics.entity.TransferStatistics; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.data.jpa.repository.QueryHints; | ||
import org.springframework.data.repository.query.Param; | ||
|
||
import jakarta.persistence.QueryHint; | ||
|
||
public interface TransferStatisticsRepository extends JpaRepository<TransferStatistics, Long> { | ||
@Query( | ||
""" | ||
SELECT ts FROM TransferStatistics ts | ||
WHERE ts.unitDate between :startDate AND :endDate | ||
ORDER BY ts.unitDate DESC | ||
""") | ||
@QueryHints(value = { | ||
@QueryHint(name = HINT_FETCH_SIZE, value = "" + Integer.MAX_VALUE), | ||
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.
|
||
@QueryHint(name = HINT_CACHEABLE, value = "false"), | ||
}) | ||
Stream<TransferStatistics> findAllByUnitDateBetween(@Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate); | ||
|
||
Optional<TransferStatistics> findByUnitDate(LocalDate date); | ||
} |
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.
전반적으로
equals
와hashCode
를 정의하고 있는데요. 혹시 해당 데이터가 HashMap 에 들어갈 것을 상정하셔서 그런걸까요?