Compare commits

1 Commits

Author SHA1 Message Date
Florian THIERRY
5b93369852 Add base 2021-03-09 00:13:13 +01:00
17 changed files with 449 additions and 0 deletions

View File

@@ -46,6 +46,12 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -0,0 +1,24 @@
package org.takiguchi.demo.intellijshortcuts.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.takiguchi.demo.intellijshortcuts.model.Game;
import org.takiguchi.demo.intellijshortcuts.service.GameService;
import java.util.List;
@RestController
@RequestMapping("/api/games")
public class GameController {
private final GameService gameService;
public GameController(GameService gameService) {
this.gameService = gameService;
}
@GetMapping
public List<Game> getAll() {
return gameService.findAll();
}
}

View File

@@ -0,0 +1,28 @@
package org.takiguchi.demo.intellijshortcuts.model;
import lombok.*;
import javax.persistence.*;
import java.time.LocalDate;
import java.util.UUID;
import static javax.persistence.FetchType.LAZY;
@Entity
@Table(name = "dlc")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Dlc {
@Id
@GeneratedValue(generator = "system-uuid")
private UUID id;
private String title;
private LocalDate publicationDate;
private Double price;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "game_id")
private Game game;
}

View File

@@ -0,0 +1,25 @@
package org.takiguchi.demo.intellijshortcuts.model;
import lombok.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.LocalDate;
import java.util.UUID;
@Entity
@Table(name = "editor")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Editor {
@Id
@GeneratedValue(generator = "system-uuid")
private UUID id;
private String name;
private LocalDate creationDate;
}

View File

@@ -0,0 +1,33 @@
package org.takiguchi.demo.intellijshortcuts.model;
import lombok.*;
import javax.persistence.*;
import java.time.LocalDate;
import java.util.List;
import java.util.UUID;
import static javax.persistence.CascadeType.*;
import static javax.persistence.FetchType.LAZY;
@Entity
@Table(name = "game")
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Game {
@Id
@GeneratedValue(generator = "system-uuid")
private UUID id;
private String title;
private String description;
private LocalDate publicationDate;
private Double price;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "editor_id")
private Editor editor;
@OneToMany(mappedBy = "game", cascade = ALL)
private List<Dlc> dlcList;
}

View File

@@ -0,0 +1,12 @@
package org.takiguchi.demo.intellijshortcuts.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.takiguchi.demo.intellijshortcuts.model.Dlc;
import java.util.UUID;
@Repository
public interface DlcRepository extends JpaRepository<Dlc, UUID> {
}

View File

@@ -0,0 +1,11 @@
package org.takiguchi.demo.intellijshortcuts.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.takiguchi.demo.intellijshortcuts.model.Editor;
import java.util.UUID;
@Repository
public interface EditorRepository extends JpaRepository<Editor, UUID> {
}

View File

@@ -0,0 +1,15 @@
package org.takiguchi.demo.intellijshortcuts.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.takiguchi.demo.intellijshortcuts.model.Game;
import java.util.List;
import java.util.UUID;
@Repository
public interface GameRepository extends JpaRepository<Game, UUID> {
@Query("SELECT DISTINCT g FROM Game g LEFT JOIN FETCH g.dlcList")
List<Game> findAllWithDlcs();
}

View File

@@ -0,0 +1,20 @@
package org.takiguchi.demo.intellijshortcuts.service;
import org.springframework.stereotype.Service;
import org.takiguchi.demo.intellijshortcuts.model.Game;
import org.takiguchi.demo.intellijshortcuts.repository.GameRepository;
import java.util.List;
@Service
public class GameService {
private final GameRepository gameRepository;
public GameService(GameRepository gameRepository) {
this.gameRepository = gameRepository;
}
public List<Game> findAll() {
return gameRepository.findAllWithDlcs();
}
}

View File

@@ -0,0 +1,37 @@
package org.takiguchi.demo.intellijshortcuts.configuration;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.takiguchi.demo.intellijshortcuts.repository.EditorRepository;
import org.takiguchi.demo.intellijshortcuts.repository.GameRepository;
import org.takiguchi.demo.intellijshortcuts.util.DatabaseInitializer;
import javax.sql.DataSource;
@TestConfiguration
@ComponentScan(basePackages = "org.takiguchi.demo.intellijshortcuts.repository")
public class RepositoryConfiguration {
@Bean
public EmbeddedDatabase dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("sql/01_init-db.sql")
.build();
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public DatabaseInitializer dataConfiguration(EditorRepository editorRepository,
GameRepository gameRepository) {
return new DatabaseInitializer(editorRepository, gameRepository);
}
}

View File

@@ -0,0 +1,16 @@
package org.takiguchi.demo.intellijshortcuts.configuration;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriBuilderFactory;
@TestConfiguration
public class TestUtilsConfiguration {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(new DefaultUriBuilderFactory("http://localhost:8080"));
return restTemplate;
}
}

View File

@@ -0,0 +1,49 @@
package org.takiguchi.demo.intellijshortcuts.controller;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.takiguchi.demo.intellijshortcuts.configuration.RepositoryConfiguration;
import org.takiguchi.demo.intellijshortcuts.configuration.TestUtilsConfiguration;
import org.takiguchi.demo.intellijshortcuts.extension.DatabaseInitializationExtension;
import org.takiguchi.demo.intellijshortcuts.model.Dlc;
import org.takiguchi.demo.intellijshortcuts.model.Game;
import java.util.Collection;
import java.util.List;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith({
SpringExtension.class,
DatabaseInitializationExtension.class
})
@SpringBootTest(classes = {
RepositoryConfiguration.class,
TestUtilsConfiguration.class
})
public class GameControllerTest {
@Autowired
private GameController gameController;
@Test
void getAll_should_fetch_dlc_list() {
// when
List<Game> games = gameController.getAll();
// then
assertThat(games).hasSize(5);
List<String> dlcTitles = games.stream()
.filter(game -> "World of Warcraft".equals(game.getTitle()))
.findFirst()
.map(Game::getDlcList)
.stream()
.flatMap(Collection::stream)
.map(Dlc::getTitle)
.collect(toList());
assertThat(dlcTitles).containsExactlyInAnyOrder("The Burning Crusade", "Wrath of the Lich King");
}
}

View File

@@ -0,0 +1,24 @@
package org.takiguchi.demo.intellijshortcuts.extension;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.takiguchi.demo.intellijshortcuts.util.DatabaseInitializer;
public class DatabaseInitializationExtension implements BeforeAllCallback, AfterAllCallback {
@Override
public void beforeAll(ExtensionContext extensionContext) {
ApplicationContext applicationContext = SpringExtension.getApplicationContext(extensionContext);
DatabaseInitializer databaseInitializer = applicationContext.getBean(DatabaseInitializer.class);
databaseInitializer.initData();
}
@Override
public void afterAll(ExtensionContext extensionContext) {
ApplicationContext applicationContext = SpringExtension.getApplicationContext(extensionContext);
DatabaseInitializer databaseInitializer = applicationContext.getBean(DatabaseInitializer.class);
databaseInitializer.clearData();
}
}

View File

@@ -0,0 +1,119 @@
package org.takiguchi.demo.intellijshortcuts.util;
import org.takiguchi.demo.intellijshortcuts.model.Dlc;
import org.takiguchi.demo.intellijshortcuts.model.Editor;
import org.takiguchi.demo.intellijshortcuts.model.Game;
import org.takiguchi.demo.intellijshortcuts.repository.EditorRepository;
import org.takiguchi.demo.intellijshortcuts.repository.GameRepository;
import java.time.LocalDate;
import java.util.List;
public class DatabaseInitializer {
private final EditorRepository editorRepository;
private final GameRepository gameRepository;
public DatabaseInitializer(EditorRepository editorRepository,
GameRepository gameRepository) {
this.editorRepository = editorRepository;
this.gameRepository = gameRepository;
}
public void initData() {
Editor psyconix = Editor.builder()
.name("Psyconix")
.creationDate(LocalDate.of(2000, 4, 30))
.build();
Editor codeMasters = Editor.builder()
.name("Codemasters")
.creationDate(LocalDate.of(1986, 1, 2))
.build();
Editor blizzard = Editor.builder()
.name("Blizzard")
.creationDate(LocalDate.of(1991, 2, 8))
.build();
editorRepository.saveAll(List.of(
psyconix,
codeMasters,
blizzard
));
Game rocketLeague = Game.builder()
.title("Rocket league")
.description("Rocket League est un mélange de jeu de voiture et de jeu de football.")
.publicationDate(LocalDate.of(2015, 7, 7))
.price(0D)
.editor(psyconix)
.build();
Game f1_2019 = Game.builder()
.title("F1 2019")
.description("Jeu de simulation de courses de F1 pour la saison 2019.")
.publicationDate(LocalDate.of(2019, 6, 28))
.price(6.99)
.editor(codeMasters)
.build();
Game f1_2020 = Game.builder()
.title("F1 2020")
.description("Jeu de simulation de courses de F1 pour la saison 2020.")
.publicationDate(LocalDate.of(2019, 7, 10))
.price(6.99)
.editor(codeMasters)
.build();
List<Dlc> warcraft3DlcList = List.of(Dlc.builder()
.title("Warcraft III: The Frozen Throne.")
.publicationDate(LocalDate.of(2003, 7, 1))
.price(14.99)
.build());
Game warcraft3 = Game.builder()
.title("Warcraft III")
.description("Jeu de stratégie en temps réel dans l'univers de Warcraft.")
.publicationDate(LocalDate.of(2002, 7, 3))
.price(49.99)
.editor(blizzard)
.dlcList(warcraft3DlcList)
.build();
warcraft3DlcList.forEach(dlc -> dlc.setGame(warcraft3));
List<Dlc> wowDlcList = List.of(
Dlc.builder()
.title("The Burning Crusade")
.publicationDate(LocalDate.of(2007, 1, 16))
.price(14.99)
.build(),
Dlc.builder()
.title("Wrath of the Lich King")
.publicationDate(LocalDate.of(2008, 11, 13))
.price(14.99)
.build()
);
Game worldOfWarcraft = Game.builder()
.title("World of Warcraft")
.description("MMORPG basé sur l'univers de Warcraft")
.publicationDate(LocalDate.of(2004, 11, 23))
.price(59.99)
.editor(blizzard)
.dlcList(wowDlcList)
.build();
wowDlcList.forEach(dlc -> dlc.setGame(worldOfWarcraft));
gameRepository.saveAll(List.of(
rocketLeague,
f1_2019,
f1_2020,
warcraft3,
worldOfWarcraft
));
}
public void clearData() {
// dlcRepository.deleteAll();
gameRepository.deleteAll();
editorRepository.deleteAll();
}
}

View File

View File

@@ -0,0 +1,30 @@
CREATE TABLE editor (
id UUID DEFAULT random_uuid() NOT NULL,
name VARCHAR NOT NULL,
creation_date DATE NOT NULL,
CONSTRAINT pk_editor PRIMARY KEY (id)
);
CREATE TABLE game (
id UUID DEFAULT random_uuid() NOT NULL,
title VARCHAR NOT NULL,
description VARCHAR NOT NULL,
publication_date DATE NOT NULL,
price NUMBER NOT NULL DEFAULT 0,
editor_id UUID NOT NULL,
CONSTRAINT pk_game PRIMARY KEY (id),
CONSTRAINT fk_game_editor_id FOREIGN KEY (editor_id) REFERENCES editor (id)
);
CREATE TABLE dlc (
id UUID DEFAULT random_uuid() NOT NULL,
title VARCHAR NOT NULL,
publication_date DATE NOT NULL,
price NUMBER NOT NULL DEFAULT 0,
game_id UUID NOT NULL,
CONSTRAINT pk_dlc PRIMARY KEY (id),
CONSTRAINT fk_dlc_game_id FOREIGN KEY (game_id) REFERENCES game (id)
);
INSERT INTO editor (name, creation_date) VALUES
('Psyonix', parsedatetime('2000-04-30', 'dd-MM-YYYY'));