Skip to content

Commit

Permalink
Improve IGDB API module structure
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Rybitskyi committed Sep 4, 2020
1 parent 27728a0 commit 6af2182
Show file tree
Hide file tree
Showing 29 changed files with 278 additions and 570 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import android.content.Context
import com.paulrybitskyi.gamedge.data.datastores.GamesDataStore
import com.paulrybitskyi.gamedge.database.datastore.GamesDatabaseDataStoreFactory
import com.paulrybitskyi.gamedge.di.qualifiers.DataStore
import com.paulrybitskyi.gamedge.igdb.api.IgdbApi
import com.paulrybitskyi.gamedge.igdb.api.datastore.GamesDataStoreImpl
import com.paulrybitskyi.gamedge.igdb.api.datastore.GamesServerDataStoreFactory
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -37,8 +36,8 @@ internal object DataStoresModule {
@Singleton
@DataStore(DataStore.Type.SERVER)
@Provides
fun provideGamesServerDataStore(igdbApi: IgdbApi): GamesDataStore {
return GamesDataStoreImpl(igdbApi)
fun provideGamesServerDataStore(): GamesDataStore {
return GamesServerDataStoreFactory.create()
}


Expand Down
1 change: 1 addition & 0 deletions igdb-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])

implementation project(deps.local.data)
implementation project(deps.local.commonsData)
implementation project(deps.local.igdbApicalypse)

implementation deps.square.okHttpLoggingInterceptor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@

package com.paulrybitskyi.gamedge.igdb.api

import com.paulrybitskyi.gamedge.igdb.api.utils.ApiCompany
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiGame
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiResult

interface IgdbApi {
internal interface IgdbApi {

suspend fun searchGames(searchQuery: String, offset: Int, limit: Int): ApiResult<List<ApiGame>>

Expand All @@ -32,8 +31,6 @@ interface IgdbApi {

suspend fun getMostAnticipatedGames(offset: Int, limit: Int): ApiResult<List<ApiGame>>

suspend fun getCompanyGames(company: ApiCompany, offset: Int, limit: Int): ApiResult<List<ApiGame>>

suspend fun getSimilarGames(game: ApiGame, offset: Int, limit: Int): ApiResult<List<ApiGame>>
suspend fun getGames(gameIds: List<Int>, offset: Int, limit: Int): ApiResult<List<ApiGame>>

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package com.paulrybitskyi.gamedge.igdb.api

import com.paulrybitskyi.gamedge.commons.data.querying.QueryTimestampProvider
import com.paulrybitskyi.gamedge.commons.data.querying.QueryTimestampProviderFactory
import com.paulrybitskyi.gamedge.igdb.api.adapters.AgeRatingCategoryAdapter
import com.paulrybitskyi.gamedge.igdb.api.adapters.AgeRatingTypeAdapter
import com.paulrybitskyi.gamedge.igdb.api.adapters.WebsiteCategoryAdapter
Expand All @@ -24,8 +26,6 @@ import com.paulrybitskyi.gamedge.igdb.api.querybuilder.IgdbApiQueryBuilderImpl
import com.paulrybitskyi.gamedge.igdb.api.services.IgdbApiService
import com.paulrybitskyi.gamedge.igdb.api.utils.AuthorizationInterceptor
import com.paulrybitskyi.gamedge.igdb.api.utils.calladapter.ApiResultCallAdapterFactory
import com.paulrybitskyi.gamedge.igdb.api.utils.providers.TimestampProvider
import com.paulrybitskyi.gamedge.igdb.api.utils.providers.TimestampProviderImpl
import com.paulrybitskyi.gamedge.igdb.apicalypse.querybuilder.ApicalypseQueryBuilderFactory
import com.paulrybitskyi.gamedge.igdb.apicalypse.serialization.ApicalypseSerializer
import com.paulrybitskyi.gamedge.igdb.apicalypse.serialization.ApicalypseSerializerFactory
Expand All @@ -36,15 +36,10 @@ import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory

object IgdbApiFactory {
internal object IgdbApiFactory {


fun createIgdbApi(): IgdbApi {
return createIgdbApiInternal()
}


private fun createIgdbApiInternal(): IgdbApi {
return IgdbApiImpl(
igdbApiService = createIgdbApiService(),
igdbApiQueryBuilder = createIgdbApiQueryBuilder()
Expand Down Expand Up @@ -105,7 +100,7 @@ object IgdbApiFactory {
return IgdbApiQueryBuilderImpl(
apicalypseQueryBuilderFactory = createApicalypseQueryBuilderFactory(),
apicalypseSerializer = createApicalypseSerializer(),
timestampProvider = createTimestampProvider()
queryTimestampProvider = createQueryTimestampProvider()
)
}

Expand All @@ -120,8 +115,8 @@ object IgdbApiFactory {
}


private fun createTimestampProvider(): TimestampProvider {
return TimestampProviderImpl()
private fun createQueryTimestampProvider(): QueryTimestampProvider {
return QueryTimestampProviderFactory.create()
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package com.paulrybitskyi.gamedge.igdb.api

import com.paulrybitskyi.gamedge.igdb.api.querybuilder.IgdbApiQueryBuilder
import com.paulrybitskyi.gamedge.igdb.api.services.IgdbApiService
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiCompany
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiGame
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiResult

Expand Down Expand Up @@ -83,29 +82,14 @@ internal class IgdbApiImpl(
}


override suspend fun getCompanyGames(
company: ApiCompany,
override suspend fun getGames(
gameIds: List<Int>,
offset: Int,
limit: Int
): ApiResult<List<ApiGame>> {
return igdbApiService.getGames(
igdbApiQueryBuilder.buildCompanyGamesRetrievalQuery(
company = company,
offset = offset,
limit = limit
)
)
}


override suspend fun getSimilarGames(
game: ApiGame,
offset: Int,
limit: Int
): ApiResult<List<ApiGame>> {
return igdbApiService.getGames(
igdbApiQueryBuilder.buildSimilarGamesRetrievalQuery(
game = game,
igdbApiQueryBuilder.buildGamesRetrievalQuery(
gameIds = gameIds,
offset = offset,
limit = limit
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
* Copyright 2020 Paul Rybitskyi, [email protected]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.paulrybitskyi.gamedge.igdb.api.datastore

import com.paulrybitskyi.gamedge.data.entities.Error as DataError
import com.paulrybitskyi.gamedge.data.utils.*
import com.paulrybitskyi.gamedge.igdb.api.entities.*
import com.paulrybitskyi.gamedge.igdb.api.entities.Error as ApiError
import com.paulrybitskyi.gamedge.igdb.api.utils.*
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiAgeRating
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiGame
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiImage
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiTimeToBeat

internal class EntityMapper {


fun mapToDataGame(apiGame: ApiGame): DataGame {
return DataGame(
id = apiGame.id,
hypeCount = apiGame.hypeCount,
releaseDate = apiGame.releaseDate,
criticsRating = apiGame.criticsRating,
usersRating = apiGame.usersRating,
totalRating = apiGame.totalRating,
popularity = apiGame.popularity,
name = apiGame.name,
summary = apiGame.summary,
storyline = apiGame.storyline,
cover = apiGame.cover.toDataImage(),
timeToBeat = apiGame.timeToBeat.toDataTimeToBeat(),
ageRatings = apiGame.ageRatings.toDataAgeRatings(),
artworks = apiGame.artworks.toDataImages(),
screenshots = apiGame.screenshots.toDataImages(),
genres = apiGame.genres.toDataGenres(),
platforms = apiGame.platforms.toDataPlatforms(),
playerPerspectives = apiGame.playerPerspectives.toDataPlayerPerspectives(),
themes = apiGame.themes.toDataThemes(),
modes = apiGame.modes.toDataModes(),
keywords = apiGame.keywords.toDataKeywords(),
involvedCompanies = apiGame.involvedCompanies.toDataInvolvedCompanies(),
websites = apiGame.websites.toDataWebsites(),
similarGames = apiGame.similarGames
)
}


private fun ApiImage.toDataImage(): DataImage {
return DataImage(
width = width,
height = height,
url = url
)
}


private fun List<ApiImage>.toDataImages(): List<DataImage> {
return map { it.toDataImage() }
}


private fun ApiTimeToBeat.toDataTimeToBeat(): DataTimeToBeat {
return DataTimeToBeat(
completely = completely,
hastily = hastily,
normally = normally
)
}


private fun List<ApiAgeRating>.toDataAgeRatings(): List<DataAgeRating> {
return map {
DataAgeRating(
category = DataAgeRatingCategory.valueOf(it.category.name),
type = DataAgeRatingType.valueOf(it.type.name)
)
}
}


private fun List<ApiGenre>.toDataGenres(): List<DataGenre> {
return map {
DataGenre(
name = it.name
)
}
}


private fun List<ApiPlatform>.toDataPlatforms(): List<DataPlatform> {
return map {
DataPlatform(
abbreviation = it.abbreviation
)
}
}


private fun List<ApiPlayerPerspective>.toDataPlayerPerspectives(): List<DataPlayerPerspective> {
return map {
DataPlayerPerspective(
name = it.name
)
}
}


private fun List<ApiTheme>.toDataThemes(): List<DataTheme> {
return map {
DataTheme(
name = it.name
)
}
}


private fun List<ApiMode>.toDataModes(): List<DataMode> {
return map {
DataMode(
name = it.name
)
}
}


private fun List<ApiKeyword>.toDataKeywords(): List<DataKeyword> {
return map {
DataKeyword(
name = it.name
)
}
}


private fun List<ApiInvolvedCompany>.toDataInvolvedCompanies(): List<DataInvolvedCompany> {
return map {
DataInvolvedCompany(
company = it.company.toDataCompany(),
isDeveloper = it.isDeveloper,
isPublisher = it.isPublisher,
isPorter = it.isPorter
)
}
}


private fun ApiCompany.toDataCompany(): DataCompany {
return DataCompany(
name = name,
developedGames = developedGames
)
}


private fun List<ApiWebsite>.toDataWebsites(): List<DataWebsite> {
return map {
DataWebsite(
url = it.url,
category = DataWebsiteCategory.valueOf(it.category.name),
isTrusted = it.isTrusted
)
}
}


fun mapToDataError(apiError: ApiError): DataError = with(apiError) {
return when {
isServerError -> DataError.ServiceUnavailable
isHttpError -> DataError.ClientError(httpErrorMessage)
isNetworkError -> DataError.NetworkError(networkErrorMessage)
isUnknownError -> DataError.Unknown(unknownErrorMessage)

else -> throw IllegalStateException("Could not map the api error $this to a data error.")
}
}


}


internal fun EntityMapper.mapToDataGames(apiGames: List<ApiGame>): List<DataGame> {
return apiGames.map(::mapToDataGame)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@

package com.paulrybitskyi.gamedge.igdb.api.datastore

import com.github.michaelbull.result.mapEither
import com.paulrybitskyi.gamedge.data.datastores.GamesDataStore
import com.paulrybitskyi.gamedge.data.utils.DataCompany
import com.paulrybitskyi.gamedge.data.utils.DataGame
import com.paulrybitskyi.gamedge.data.utils.DataStoreResult
import com.paulrybitskyi.gamedge.igdb.api.IgdbApi
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiGame
import com.paulrybitskyi.gamedge.igdb.api.utils.ApiResult

class GamesDataStoreImpl(
private val igdbApi: IgdbApi
internal class GamesServerDataStore(
private val igdbApi: IgdbApi,
private val entityMapper: EntityMapper
) : GamesDataStore {


Expand Down Expand Up @@ -64,16 +68,24 @@ class GamesDataStoreImpl(

override suspend fun getCompanyGames(company: DataCompany, offset: Int, limit: Int): DataStoreResult<List<DataGame>> {
return igdbApi
.getCompanyGames(company.toApiCompany(), offset, limit)
.getGames(company.developedGames, offset, limit)
.toDataStoreResult()
}


override suspend fun getSimilarGames(game: DataGame, offset: Int, limit: Int): DataStoreResult<List<DataGame>> {
return igdbApi
.getSimilarGames(game.toApiGame(), offset, limit)
.getGames(game.similarGames, offset, limit)
.toDataStoreResult()
}


private fun ApiResult<List<ApiGame>>.toDataStoreResult(): DataStoreResult<List<DataGame>> {
return mapEither(
success = entityMapper::mapToDataGames,
failure = entityMapper::mapToDataError
)
}


}
Loading

0 comments on commit 6af2182

Please sign in to comment.