#33 tdd(order-service): add product - jpa

This commit is contained in:
haerong22
2023-02-08 01:06:54 +09:00
parent 6c82ac7d6c
commit 305d0369c3
7 changed files with 101 additions and 20 deletions

View File

@@ -21,6 +21,8 @@ repositories {
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.google.guava:guava:31.1-jre'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'

View File

@@ -1,12 +1,23 @@
package com.example.productorderservice.product;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.util.Assert;
import javax.persistence.*;
@Entity
@Table(name = "products")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private final String name;
private final int price;
private final DiscountPolicy discountPolicy;
private String name;
private int price;
private DiscountPolicy discountPolicy;
public Product(String name, int price, DiscountPolicy discountPolicy) {
Assert.hasText(name, "상품명은 필수입니다.");
@@ -18,11 +29,4 @@ class Product {
this.discountPolicy = discountPolicy;
}
public void assignId(final Long id) {
this.id = id;
}
public Long getId() {
return id;
}
}

View File

@@ -1,17 +1,18 @@
package com.example.productorderservice.product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.Map;
@Repository
class ProductRepository {
private Map<Long, Product> persistence = new HashMap<>();
private Long sequence = 0L;
public void save(final Product product) {
product.assignId(++sequence);
persistence.put(product.getId(), product);
}
interface ProductRepository extends JpaRepository<Product, Long> {
// private Map<Long, Product> persistence = new HashMap<>();
// private Long sequence = 0L;
//
// public void save(final Product product) {
// product.assignId(++sequence);
// persistence.put(product.getId(), product);
// }
}

View File

@@ -1,6 +1,7 @@
package com.example.productorderservice.product;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
class ProductService {
@@ -11,6 +12,7 @@ class ProductService {
}
@Transactional
public void addProduct(AddProductRequest request) {
final Product product = new Product(request.name(), request.price(), request.discountPolicy());

View File

@@ -1 +1,2 @@
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true

View File

@@ -2,17 +2,25 @@ package com.example.productorderservice;
import io.restassured.RestAssured;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class ApiTest {
@Autowired
private DatabaseCleanup databaseCleanup;
@LocalServerPort
private int port;
@BeforeEach
void setUp() {
RestAssured.port = port;
if (RestAssured.port == RestAssured.UNDEFINED_PORT) {
RestAssured.port = port;
databaseCleanup.afterPropertiesSet();
}
databaseCleanup.execute();
}
}

View File

@@ -0,0 +1,63 @@
package com.example.productorderservice;
import com.google.common.base.CaseFormat;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Table;
import javax.persistence.metamodel.EntityType;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@Component
public class DatabaseCleanup implements InitializingBean {
@PersistenceContext
private EntityManager entityManager;
private List<String> tableNames;
@Override
public void afterPropertiesSet() {
final Set<EntityType<?>> entities = entityManager.getMetamodel().getEntities();
tableNames = entities.stream()
.filter(e -> isEntity(e) && hasTableAnnotation(e))
.map(e -> {
String tableName = e.getJavaType().getAnnotation(Table.class).name();
return tableName.isBlank() ? CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, e.getName()) : tableName;
})
.collect(Collectors.toList());
final List<String> entityNames = entities.stream()
.filter(e -> isEntity(e) && !hasTableAnnotation(e))
.map(e -> CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, e.getName()))
.toList();
tableNames.addAll(entityNames);
}
private boolean isEntity(final EntityType<?> e) {
return null != e.getJavaType().getAnnotation(Entity.class);
}
private boolean hasTableAnnotation(final EntityType<?> e) {
return null != e.getJavaType().getAnnotation(Table.class);
}
@Transactional
public void execute() {
entityManager.flush();
entityManager.createNativeQuery("SET REFERENTIAL_INTEGRITY FALSE").executeUpdate();
for (final String tableName : tableNames) {
entityManager.createNativeQuery("TRUNCATE TABLE " + tableName).executeUpdate();
entityManager.createNativeQuery("ALTER TABLE " + tableName + " ALTER COLUMN ID RESTART WITH 1").executeUpdate();
}
entityManager.createNativeQuery("SET REFERENTIAL_INTEGRITY TRUE").executeUpdate();
}
}