Skip to content

Commit 628ab3d

Browse files
committed
Added repositories and use cases
1 parent 6f0972c commit 628ab3d

12 files changed

+310
-0
lines changed

Pokemon/Pokemon.xcodeproj/project.pbxproj

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929
DAD0D37A2840B82F00436272 /* DBPokemon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D3792840B82F00436272 /* DBPokemon.swift */; };
3030
DAD0D37C2840B85100436272 /* DBPokemonType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D37B2840B85100436272 /* DBPokemonType.swift */; };
3131
DAD0D37F2840BEAA00436272 /* DateFormatter+Pokemon.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D37E2840BEAA00436272 /* DateFormatter+Pokemon.swift */; };
32+
DAD0D3812840C29900436272 /* PokemonRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D3802840C29900436272 /* PokemonRepository.swift */; };
33+
DAD0D3832840C45300436272 /* LocalPokemonDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D3822840C45300436272 /* LocalPokemonDataSource.swift */; };
34+
DAD0D3852840C4C800436272 /* RemotePokemonDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D3842840C4C800436272 /* RemotePokemonDataSource.swift */; };
35+
DAD0D3872840C65D00436272 /* PokemonRepositoryImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D3862840C65D00436272 /* PokemonRepositoryImplementation.swift */; };
36+
DAD0D3892840C76700436272 /* GetPokemonUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D3882840C76700436272 /* GetPokemonUseCase.swift */; };
37+
DAD0D38B2840C7C600436272 /* SavePokemonUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D38A2840C7C600436272 /* SavePokemonUseCase.swift */; };
38+
DAD0D38D2840C7FE00436272 /* ExistsPokemonUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D38C2840C7FE00436272 /* ExistsPokemonUseCase.swift */; };
39+
DAD0D38F2840C83100436272 /* GetPokemonsUseCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAD0D38E2840C83100436272 /* GetPokemonsUseCase.swift */; };
3240
/* End PBXBuildFile section */
3341

3442
/* Begin PBXContainerItemProxy section */
@@ -74,6 +82,14 @@
7482
DAD0D3792840B82F00436272 /* DBPokemon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBPokemon.swift; sourceTree = "<group>"; };
7583
DAD0D37B2840B85100436272 /* DBPokemonType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBPokemonType.swift; sourceTree = "<group>"; };
7684
DAD0D37E2840BEAA00436272 /* DateFormatter+Pokemon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Pokemon.swift"; sourceTree = "<group>"; };
85+
DAD0D3802840C29900436272 /* PokemonRepository.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokemonRepository.swift; sourceTree = "<group>"; };
86+
DAD0D3822840C45300436272 /* LocalPokemonDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalPokemonDataSource.swift; sourceTree = "<group>"; };
87+
DAD0D3842840C4C800436272 /* RemotePokemonDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemotePokemonDataSource.swift; sourceTree = "<group>"; };
88+
DAD0D3862840C65D00436272 /* PokemonRepositoryImplementation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokemonRepositoryImplementation.swift; sourceTree = "<group>"; };
89+
DAD0D3882840C76700436272 /* GetPokemonUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetPokemonUseCase.swift; sourceTree = "<group>"; };
90+
DAD0D38A2840C7C600436272 /* SavePokemonUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SavePokemonUseCase.swift; sourceTree = "<group>"; };
91+
DAD0D38C2840C7FE00436272 /* ExistsPokemonUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExistsPokemonUseCase.swift; sourceTree = "<group>"; };
92+
DAD0D38E2840C83100436272 /* GetPokemonsUseCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetPokemonsUseCase.swift; sourceTree = "<group>"; };
7793
/* End PBXFileReference section */
7894

7995
/* Begin PBXFrameworksBuildPhase section */
@@ -167,6 +183,10 @@
167183
DAD0D353283FCD2B00436272 /* UseCases */ = {
168184
isa = PBXGroup;
169185
children = (
186+
DAD0D3882840C76700436272 /* GetPokemonUseCase.swift */,
187+
DAD0D38A2840C7C600436272 /* SavePokemonUseCase.swift */,
188+
DAD0D38C2840C7FE00436272 /* ExistsPokemonUseCase.swift */,
189+
DAD0D38E2840C83100436272 /* GetPokemonsUseCase.swift */,
170190
);
171191
path = UseCases;
172192
sourceTree = "<group>";
@@ -222,6 +242,10 @@
222242
DAD0D359283FCD2B00436272 /* Repositories */ = {
223243
isa = PBXGroup;
224244
children = (
245+
DAD0D3802840C29900436272 /* PokemonRepository.swift */,
246+
DAD0D3822840C45300436272 /* LocalPokemonDataSource.swift */,
247+
DAD0D3842840C4C800436272 /* RemotePokemonDataSource.swift */,
248+
DAD0D3862840C65D00436272 /* PokemonRepositoryImplementation.swift */,
225249
);
226250
path = Repositories;
227251
sourceTree = "<group>";
@@ -386,17 +410,25 @@
386410
DAD0D3782840B7A000436272 /* ServerSprite.swift in Sources */,
387411
DAD0D37F2840BEAA00436272 /* DateFormatter+Pokemon.swift in Sources */,
388412
DAD0D36D283FD40100436272 /* HTTPError.swift in Sources */,
413+
DAD0D3852840C4C800436272 /* RemotePokemonDataSource.swift in Sources */,
389414
DAD0D3762840B6D800436272 /* Model.xcdatamodeld in Sources */,
415+
DAD0D3832840C45300436272 /* LocalPokemonDataSource.swift in Sources */,
416+
DAD0D38D2840C7FE00436272 /* ExistsPokemonUseCase.swift in Sources */,
417+
DAD0D3812840C29900436272 /* PokemonRepository.swift in Sources */,
390418
DAD0D35F283FCF1500436272 /* ServerTypes.swift in Sources */,
391419
DAD0D36B283FD3B300436272 /* APIManager.swift in Sources */,
420+
DAD0D3892840C76700436272 /* GetPokemonUseCase.swift in Sources */,
392421
DAD0D31C283FC74100436272 /* PokemonApp.swift in Sources */,
393422
DAD0D352283FC7B000436272 /* Constants.swift in Sources */,
394423
DAD0D3712840B50200436272 /* CoreDataStack.swift in Sources */,
424+
DAD0D3872840C65D00436272 /* PokemonRepositoryImplementation.swift in Sources */,
395425
DAD0D369283FD1A600436272 /* Pokemon.swift in Sources */,
396426
DAD0D37A2840B82F00436272 /* DBPokemon.swift in Sources */,
397427
DAD0D35D283FCD3A00436272 /* ServerPokemon.swift in Sources */,
398428
DAD0D36F283FDA2F00436272 /* Persistence.swift in Sources */,
429+
DAD0D38B2840C7C600436272 /* SavePokemonUseCase.swift in Sources */,
399430
DAD0D367283FD0B400436272 /* PokemonType.swift in Sources */,
431+
DAD0D38F2840C83100436272 /* GetPokemonsUseCase.swift in Sources */,
400432
DAD0D3732840B60F00436272 /* DBManager.swift in Sources */,
401433
DAD0D37C2840B85100436272 /* DBPokemonType.swift in Sources */,
402434
);

Pokemon/Pokemon/DataBase/CoreDataStack.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class CoreDataStack {
2525
}()
2626

2727
lazy var managedContext: NSManagedObjectContext = {
28+
2829
return storeContainer.viewContext
2930
}()
3031

Pokemon/Pokemon/DataBase/DBManager.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,27 @@ class DBManager: Persistence {
5252
coreDataStack.saveContext()
5353
}
5454

55+
func existsPokemon(pokemon: Pokemon) -> Bool {
56+
57+
let pokemonId = Int64(pokemon.id)
58+
59+
let fetchRequest = NSFetchRequest<DBPokemon>(entityName: "DBPokemon")
60+
fetchRequest.predicate = NSPredicate(format: "id==\(pokemonId)")
61+
62+
do {
63+
64+
let dbPokemons = try coreDataStack.managedContext.fetch(fetchRequest)
65+
66+
return dbPokemons.first != nil
67+
68+
} catch let error as NSError {
69+
70+
print("Could not fetch pokemon with \(pokemonId). \(error), \(error.userInfo)")
71+
72+
return false
73+
}
74+
}
75+
5576
func getPokemons() -> [Pokemon] {
5677

5778
var pokemons: [Pokemon] = []

Pokemon/Pokemon/DataBase/Persistence.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ protocol Persistence {
1414
*/
1515
func savePokemon(pokemon: Pokemon)
1616

17+
/**
18+
Check if this pokemon already has been caught
19+
*/
20+
func existsPokemon(pokemon: Pokemon) -> Bool
21+
1722
/**
1823
Get all pokemons from DB
1924
*/
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// LocalPokemonDataSource.swift
3+
// Pokemon
4+
//
5+
// Created by Xavier Ramos on 27/5/22.
6+
//
7+
8+
import Foundation
9+
10+
class LocalPokemonDataSource {
11+
12+
private let dbManager: Persistence
13+
14+
init(dbManager: Persistence = DBManager()) {
15+
16+
self.dbManager = dbManager
17+
}
18+
19+
func savePokemon(pokemon: Pokemon) {
20+
21+
dbManager.savePokemon(pokemon: pokemon)
22+
}
23+
24+
func existsPokemon(pokemon: Pokemon) -> Bool {
25+
26+
return dbManager.existsPokemon(pokemon: pokemon)
27+
}
28+
29+
func getPokemons() -> [Pokemon] {
30+
31+
return dbManager.getPokemons()
32+
}
33+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// PokemonRepository.swift
3+
// Pokemon
4+
//
5+
// Created by Xavier Ramos on 27/5/22.
6+
//
7+
8+
import Foundation
9+
import Combine
10+
11+
protocol PokemonRepository {
12+
13+
func getPokemon() -> AnyPublisher<Pokemon, Error>
14+
15+
func savePokemon(pokemon: Pokemon)
16+
func existsPokemon(pokemon: Pokemon) -> Bool
17+
func getPokemons() -> [Pokemon]
18+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// PokemonRepositoryImplementation.swift
3+
// Pokemon
4+
//
5+
// Created by Xavier Ramos on 27/5/22.
6+
//
7+
8+
import Foundation
9+
import Combine
10+
import UIKit
11+
12+
class PokemonRepositoryImplementation: PokemonRepository {
13+
14+
// MARK: - Properties
15+
16+
private let remoteDataSource: RemotePokemonDataSource
17+
private let localDataSource: LocalPokemonDataSource
18+
19+
// MARK: - Methods
20+
21+
init(remoteDataSource: RemotePokemonDataSource = RemotePokemonDataSource(),
22+
localDataSource: LocalPokemonDataSource = LocalPokemonDataSource()) {
23+
24+
self.remoteDataSource = remoteDataSource
25+
self.localDataSource = localDataSource
26+
}
27+
28+
// MARK: - PokemonRepository
29+
30+
func getPokemon() -> AnyPublisher<Pokemon, Error> {
31+
32+
return remoteDataSource.getPokemon().map { serverPokemon -> Pokemon in
33+
34+
// convert to entity
35+
let pokemon = serverPokemon.convertToEntity()
36+
37+
return pokemon
38+
}
39+
.mapError({ $0 })
40+
.eraseToAnyPublisher()
41+
}
42+
43+
func savePokemon(pokemon: Pokemon) {
44+
45+
localDataSource.savePokemon(pokemon: pokemon)
46+
}
47+
48+
func existsPokemon(pokemon: Pokemon) -> Bool {
49+
50+
return localDataSource.existsPokemon(pokemon: pokemon)
51+
}
52+
53+
func getPokemons() -> [Pokemon] {
54+
55+
return localDataSource.getPokemons()
56+
}
57+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//
2+
// RemotePokemonDataSource.swift
3+
// Pokemon
4+
//
5+
// Created by Xavier Ramos on 27/5/22.
6+
//
7+
8+
import Foundation
9+
import Combine
10+
11+
class RemotePokemonDataSource {
12+
13+
static let getPokemonURL: String = "pokemon/"
14+
15+
private let baseURL: String
16+
private let session: URLSession
17+
18+
init(baseURL: String = Constants.baseURL, session: URLSession = URLSession.shared) {
19+
20+
self.baseURL = baseURL
21+
self.session = session
22+
}
23+
24+
func getPokemon() -> AnyPublisher<ServerPokemon, Error> {
25+
26+
let apiManager = ApiManager(baseURL: baseURL, session: session)
27+
28+
let urlRequest = getPokemonEndpoint()
29+
30+
return apiManager.performRequest(urlRequest: urlRequest)
31+
}
32+
}
33+
34+
// MARK: - Endpoints
35+
36+
extension RemotePokemonDataSource {
37+
38+
func getPokemonEndpoint() -> URLRequest {
39+
40+
let id: Int = Int.random(in: 1..<1000)
41+
42+
let endpoint = "\(baseURL)\(RemotePokemonDataSource.getPokemonURL)\(id)"
43+
44+
let url = URL(string: endpoint)
45+
46+
let urlRequest = URLRequest(url: url!)
47+
48+
return urlRequest
49+
}
50+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// ExistsPokemonUseCase.swift
3+
// Pokemon
4+
//
5+
// Created by Xavier Ramos on 27/5/22.
6+
//
7+
8+
import Foundation
9+
10+
class ExistsPokemonUseCase {
11+
12+
private let repository: PokemonRepository
13+
14+
init(repository: PokemonRepository = PokemonRepositoryImplementation()) {
15+
16+
self.repository = repository
17+
}
18+
19+
func execute(pokemon: Pokemon) -> Bool {
20+
21+
return repository.existsPokemon(pokemon: pokemon)
22+
}
23+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//
2+
// GetPokemonUseCase.swift
3+
// Pokemon
4+
//
5+
// Created by Xavier Ramos on 27/5/22.
6+
//
7+
8+
import Foundation
9+
import Combine
10+
11+
class GetPokemonUseCase {
12+
13+
private let repository: PokemonRepository
14+
15+
init(repository: PokemonRepository = PokemonRepositoryImplementation()) {
16+
17+
self.repository = repository
18+
}
19+
20+
func execute() -> AnyPublisher<Pokemon, Error> {
21+
22+
return repository.getPokemon()
23+
}
24+
}

0 commit comments

Comments
 (0)