Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.videogamescatalogue.backend.dto.external;

public record ApiResponseDeveloperDto(
Long id,
String name
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public record ApiResponseFullGameDto(

List<ApiResponseGenreDto> genres,

List<ApiResponseDeveloperDto> developers,

BigDecimal rating
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.videogamescatalogue.backend.dto.internal.developer;

public record DeveloperDto(
Long id,
Long apiId,
String name
) {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.videogamescatalogue.backend.dto.internal.game;

import com.videogamescatalogue.backend.dto.internal.developer.DeveloperDto;
import com.videogamescatalogue.backend.dto.internal.genre.GenreDto;
import com.videogamescatalogue.backend.dto.internal.platform.PlatformDto;
import java.math.BigDecimal;
Expand All @@ -12,6 +13,7 @@ public record GameDto(
String backgroundImage,
Set<PlatformDto> platforms,
Set<GenreDto> genres,
Set<DeveloperDto> developers,
BigDecimal apiRating,
String description
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.videogamescatalogue.backend.dto.internal.game;

import com.videogamescatalogue.backend.dto.internal.developer.DeveloperDto;
import com.videogamescatalogue.backend.dto.internal.genre.GenreDto;
import com.videogamescatalogue.backend.dto.internal.platform.PlatformDto;
import com.videogamescatalogue.backend.model.UserGame;
Expand All @@ -13,6 +14,7 @@ public record GameWithStatusDto(
String backgroundImage,
Set<PlatformDto> platforms,
Set<GenreDto> genres,
Set<DeveloperDto> developers,
BigDecimal apiRating,
String description,
UserGame.GameStatus status
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.videogamescatalogue.backend.mapper.developer;

import com.videogamescatalogue.backend.config.MapperConfig;
import com.videogamescatalogue.backend.dto.external.ApiResponseDeveloperDto;
import com.videogamescatalogue.backend.dto.internal.developer.DeveloperDto;
import com.videogamescatalogue.backend.model.Developer;
import java.util.List;
import java.util.Set;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(config = MapperConfig.class)
public interface DeveloperMapper {
@Mapping(source = "id", target = "apiId")
@Mapping(target = "id", ignore = true)
Developer toModel(ApiResponseDeveloperDto apiResponseDeveloperDto);

Set<Developer> toModelSet(List<ApiResponseDeveloperDto> developers);

Set<DeveloperDto> toDtoSet(Set<Developer> developers);

DeveloperDto toDto(Developer developer);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.videogamescatalogue.backend.mapper.developer;

import com.videogamescatalogue.backend.dto.external.ApiResponseDeveloperDto;
import com.videogamescatalogue.backend.dto.internal.developer.DeveloperDto;
import com.videogamescatalogue.backend.model.Developer;
import com.videogamescatalogue.backend.repository.DeveloperRepository;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.mapstruct.Named;
import org.springframework.stereotype.Component;

@RequiredArgsConstructor
@Component
public class DeveloperProvider {
private final DeveloperMapper developerMapper;
private final DeveloperRepository developerRepository;

@Named("toDevelopersSet")
public Set<Developer> toDevelopersSet(List<ApiResponseDeveloperDto> developers) {
List<Long> developerApiIds = developers.stream()
.map(ApiResponseDeveloperDto::id)
.toList();

List<Developer> existingDevelopers = developerRepository.findAllByApiIdIn(developerApiIds);

Map<Long, Developer> existingDevelopersMap = existingDevelopers.stream()
.collect(Collectors.toMap(
Developer::getApiId,
d -> d
));

Set<Developer> developersSet = developers.stream()
.map(d -> existingDevelopersMap.getOrDefault(
d.id(),
developerMapper.toModel(d)))
.collect(Collectors.toSet());

return developersSet;
}

@Named("toDeveloperDtosSet")
public Set<DeveloperDto> toDeveloperDtosSet(Set<Developer> developers) {
return developerMapper.toDtoSet(developers);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.videogamescatalogue.backend.dto.internal.game.GameDto;
import com.videogamescatalogue.backend.dto.internal.game.GameWithStatusDto;
import com.videogamescatalogue.backend.exception.ParsingException;
import com.videogamescatalogue.backend.mapper.developer.DeveloperProvider;
import com.videogamescatalogue.backend.mapper.genre.GenreProvider;
import com.videogamescatalogue.backend.mapper.platform.PlatformProvider;
import com.videogamescatalogue.backend.model.Game;
Expand All @@ -17,7 +18,11 @@
import org.mapstruct.Mapping;
import org.mapstruct.Named;

@Mapper(config = MapperConfig.class, uses = {PlatformProvider.class, GenreProvider.class})
@Mapper(config = MapperConfig.class, uses = {
PlatformProvider.class,
GenreProvider.class,
DeveloperProvider.class
})
public interface GameMapper {
List<Game> toModelList(List<ApiResponseGameDto> games);

Expand All @@ -34,14 +39,20 @@ public interface GameMapper {
@Mapping(source = "released", target = "year", qualifiedByName = "toYear")
@Mapping(source = "platforms", target = "platforms", qualifiedByName = "toPlatformsSet")
@Mapping(source = "genres", target = "genres", qualifiedByName = "toGenresSet")
@Mapping(source = "developers", target = "developers", qualifiedByName = "toDevelopersSet")
@Mapping(source = "rating", target = "apiRating")
Game toModel(ApiResponseFullGameDto apiResponseGameDto);

@Mapping(source = "platforms", target = "platforms", qualifiedByName = "toPlatformDtosSet")
@Mapping(source = "genres", target = "genres", qualifiedByName = "toGenreDtosSet")
@Mapping(source = "developers", target = "developers", qualifiedByName = "toDeveloperDtosSet")
GameDto toDto(Game game);

@Mapping(target = "status", source = "status")
@Mapping(
source = "game.developers", target = "developers",
qualifiedByName = "toDeveloperDtosSet"
)
GameWithStatusDto toDtoWithStatus(Game game, UserGame.GameStatus status);

@Named("toYear")
Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/videogamescatalogue/backend/model/Developer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.videogamescatalogue.backend.model;

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.Getter;
import lombok.Setter;

@Entity
@Table(name = "developers")
@Getter
@Setter
public class Developer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, unique = true)
private Long apiId;

@Column(nullable = false)
private String name;
}
9 changes: 9 additions & 0 deletions src/main/java/com/videogamescatalogue/backend/model/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ public class Game {
)
private Set<Genre> genres = new HashSet<>();

@ManyToMany
@JoinTable(
name = "games_developers",
joinColumns = @JoinColumn(name = "game_id"),
inverseJoinColumns = @JoinColumn(name = "developer_id"),
uniqueConstraints = @UniqueConstraint(columnNames = {"game_id", "developer_id"})
)
private Set<Developer> developers = new HashSet<>();

private BigDecimal apiRating;

private String description;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.videogamescatalogue.backend.repository;

import com.videogamescatalogue.backend.model.Developer;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;

public interface DeveloperRepository extends JpaRepository<Developer, Long> {
Optional<Developer> findByApiId(Long apiId);

List<Developer> findAllByApiIdIn(List<Long> apiIds);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,23 @@
import com.videogamescatalogue.backend.dto.internal.GameSearchParameters;
import com.videogamescatalogue.backend.dto.internal.game.GameDto;
import com.videogamescatalogue.backend.dto.internal.game.GameWithStatusDto;
import com.videogamescatalogue.backend.mapper.developer.DeveloperMapper;
import com.videogamescatalogue.backend.mapper.game.GameMapper;
import com.videogamescatalogue.backend.model.Developer;
import com.videogamescatalogue.backend.model.Game;
import com.videogamescatalogue.backend.model.User;
import com.videogamescatalogue.backend.model.UserGame;
import com.videogamescatalogue.backend.repository.DeveloperRepository;
import com.videogamescatalogue.backend.repository.GameRepository;
import com.videogamescatalogue.backend.repository.SpecificationBuilder;
import com.videogamescatalogue.backend.repository.UserGameRepository;
import com.videogamescatalogue.backend.service.RawgApiClient;
import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
Expand All @@ -32,9 +37,11 @@
public class GameServiceImpl implements GameService {
private final RawgApiClient apiClient;
private final GameMapper gameMapper;
private final DeveloperMapper developerMapper;
private final GameRepository gameRepository;
private final SpecificationBuilder<Game, GameSearchParameters> specificationBuilder;
private final UserGameRepository userGameRepository;
private final DeveloperRepository developerRepository;

@Override
public void fetchBestGames() {
Expand Down Expand Up @@ -82,6 +89,7 @@ public Page<GameDto> getAllGamesFromDb(Pageable pageable) {
.map(gameMapper::toDto);
}

@Transactional
@Override
public GameWithStatusDto getByApiId(Long apiId, User user) {
Game game = findOrUpdate(apiId);
Expand Down Expand Up @@ -154,15 +162,26 @@ private Game findOrUpdate(Long apiId) {
}
Game game = gameOptional.get();
if (game.getDescription() == null) {
return updateGameDescription(apiId, game);
updateGameDescription(apiId, game);
}
if (game.getDevelopers().isEmpty()) {
updateGameDevelopers(apiId, game);
}
return game;
}

private Game updateGameDescription(Long apiId, Game game) {
private void updateGameDescription(Long apiId, Game game) {
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
game.setDescription(apiGame.description());
return gameRepository.save(game);
gameRepository.save(game);
}

private void updateGameDevelopers(Long apiId, Game game) {
ApiResponseFullGameDto apiGame = apiClient.getGameById(apiId);
Set<Developer> developers = developerMapper.toModelSet(apiGame.developers());
developerRepository.saveAll(developers);
game.setDevelopers(developers);
gameRepository.save(game);
}

private Game findFromApi(Long apiId) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
databaseChangeLog:
- changeSet:
id: create-developers-table
author: julia
preConditions:
- onFail: MARK_RAN
- not:
- tableExists:
tableName: developers
changes:
- createTable:
tableName: developers
columns:
- column:
name: id
type: BIGINT
autoIncrement: true
constraints:
primaryKey: true
nullable: false

- column:
name: api_id
type: BIGINT
constraints:
nullable: false
unique: true

- column:
name: name
type: VARCHAR(200)
constraints:
nullable: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
databaseChangeLog:
- changeSet:
id: create-games-developers-table
author: julia
preConditions:
- onFail: MARK_RAN
- not:
- tableExists:
tableName: games_developers
changes:
- createTable:
tableName: games_developers
columns:
- column:
name: game_id
type: BIGINT
constraints:
nullable: false

- column:
name: developer_id
type: BIGINT
constraints:
nullable: false

- addPrimaryKey:
tableName: games_developers
columnNames: game_id, developer_id
constraintName: pk_games_developers

- addForeignKeyConstraint:
baseTableName: games_developers
baseColumnNames: game_id
referencedTableName: games
referencedColumnNames: id
constraintName: fk_games_developers_game

- addForeignKeyConstraint:
baseTableName: games_developers
baseColumnNames: developer_id
referencedTableName: developers
referencedColumnNames: id
constraintName: fk_games_developers_developer
4 changes: 4 additions & 0 deletions src/main/resources/db/changelog/db.changelog-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ databaseChangeLog:
file: classpath:/db/changelog/changes/14-create-user-game-table.yaml
- include:
file: classpath:/db/changelog/changes/15-create-comments-table.yaml
- include:
file: classpath:/db/changelog/changes/16-create-developers-table.yaml
- include:
file: classpath:/db/changelog/changes/17-create-games-developers-table.yaml
Loading