Skip to content

Commit 829e519

Browse files
author
Aarif Sumra
committed
fix: error building and added latest code
1 parent 229d88f commit 829e519

38 files changed

+483
-537
lines changed

{{cookiecutter.app_name}}/Domain/Entities/{{cookiecutter.domain_model}}.swift

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,21 @@
88

99
import Foundation
1010

11+
public protocol {{cookiecutter.domain_model}}Entity: Entity {
12+
// Required
13+
var id: String { get }
14+
var title: String { get }
15+
// `Optional`s
16+
var body: String? { get }
17+
}
18+
19+
// Conformance to codable done here because it can not be done as extension. Proper place would be in the Platform module
1120
public struct {{cookiecutter.domain_model}}: Codable {
1221
// Required
1322
public let id: Int
1423
public let title: String
15-
public let posterPath: String?
16-
// Optionals
17-
public private(set) var status: String?
18-
19-
public init(id: Int, title: String, posterPath: String?, status: String? = nil) {
20-
self.id = id
21-
self.title = title
22-
self.posterPath = posterPath
23-
self.status = status
24-
}
24+
// `Optional`s
25+
public private(set) var body: String? = nil
2526
}
2627

2728
extension {{cookiecutter.domain_model}}: Hashable {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//
2+
// Entity.swift
3+
// Domain
4+
//
5+
// Created by {{cookiecutter.lead_dev_name}} on {% now 'local' %}.
6+
// Copyright © {% now 'local', '%Y' %} {{cookiecutter.company_name}} All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public protocol Entity {
12+
var id: Int { get }
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//
2+
// UseCase.swift
3+
// Domain
4+
//
5+
// Created by {{cookiecutter.lead_dev_name}} on {% now 'local' %}.
6+
// Copyright © {% now 'local', '%Y' %} {{cookiecutter.company_name}} All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public protocol UseCase {
12+
13+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// {{cookiecutter.domain_model}}sEndpoint.swift
3+
// Platform
4+
//
5+
// Created by {{cookiecutter.lead_dev_name}} on {% now 'local' %}.
6+
// Copyright © 2021 {{cookiecutter.company_name}} All rights reserved.
7+
//
8+
9+
import Domain
10+
11+
enum Endpoints: Endpoint {
12+
case {{cookiecutter.domain_model|lower}}s
13+
14+
var relativePath: String {
15+
switch self {
16+
case .{{cookiecutter.domain_model|lower}}s:
17+
return "{{cookiecutter.domain_model|lower}}s"
18+
}
19+
}
20+
21+
var headers: [String : String] {
22+
return [
23+
"Content-Type": "application/json"
24+
]
25+
}
26+
}

{{cookiecutter.app_name}}/Platform/Network/Endpoints/{{cookiecutter.domain_model}}sEndpoint.swift

Lines changed: 0 additions & 18 deletions
This file was deleted.

{{cookiecutter.app_name}}/Platform/Network/Network.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public class Network: Networking {
1313
public init(session: URLSession) {
1414
self.session = session
1515
}
16+
17+
static let `default` = {
18+
Network(session: URLSession.shared)
19+
}()
1620

1721
public func send(_ request: URLRequest, completion: @escaping (Result<Data, NetworkingError>) -> Void) {
1822
let task = session.dataTask(with: request) { data, response, error in

{{cookiecutter.app_name}}/Platform/Protocols/Endpoint.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
import Domain
1010

1111
protocol Endpoint {
12-
associatedtype Resource: Codable
13-
static var method: HTTPMethod { get }
14-
static var relativePath: String { get }
15-
static var headers: [String: String] { get }
12+
var relativePath: String { get }
13+
var headers: [String: String] { get }
1614
}

{{cookiecutter.app_name}}/Platform/Protocols/RepositoryType.swift

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@
99
import Domain
1010
import Combine
1111

12-
public enum RepositoryError: Error {
12+
enum RepositoryError: Error {
1313
case queryFailed(Error)
1414
case saveFailed
1515
case deleteFailed
1616
}
1717

18-
public protocol RepositoryType: class {
18+
protocol RepositoryType: class {
1919
associatedtype T
2020
func queryAll(_ completion: @escaping (Result<[T], Error>) -> Void)
21-
func query(with queryString: String, completion: @escaping (Result<[T], Error>) -> Void)
21+
func query(withId id: Int, completion: @escaping (Result<T, Error>) -> Void)
22+
func query(withQueryItems queryItems: [URLQueryItem], completion: @escaping (Result<[T], Error>) -> Void)
2223
func save(entity: T, completion: @escaping (Error?) -> Void)
2324
func delete(entity: T, completion: @escaping (Error?) -> Void)
2425
}
@@ -29,9 +30,17 @@ extension RepositoryType where Self: Combinable {
2930
Future(queryAll).eraseToAnyPublisher()
3031
}
3132

32-
func queryPublisher(for queryString: String) -> AnyPublisher<[T], Error> {
33+
func queryPublisher(forId id: Int) -> AnyPublisher<T, Error> {
3334
Future { promise in
34-
self.query(with: queryString) { result in
35+
self.query(withId: id) { result in
36+
promise(result)
37+
}
38+
}.eraseToAnyPublisher()
39+
}
40+
41+
func queryPublisher(forQueryItems queryItems: [URLQueryItem]) -> AnyPublisher<[T], Error> {
42+
Future { promise in
43+
self.query(withQueryItems: queryItems) { result in
3544
promise(result)
3645
}
3746
}.eraseToAnyPublisher()

{{cookiecutter.app_name}}/Platform/Repository/List/{{cookiecutter.domain_model}}sRepository.swift

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,31 @@ final class {{cookiecutter.domain_model}}sRepository {
1515
case notFound
1616
}
1717

18-
private let repository: RemoteRepository<{{cookiecutter.domain_model}}sEndpoint>
18+
private let repository: RemoteRepository<{{cookiecutter.domain_model}}>
1919

20-
init(repository: RemoteRepository<{{cookiecutter.domain_model}}sEndpoint>) {
20+
init(repository: RemoteRepository<{{cookiecutter.domain_model}}>) {
2121
self.repository = repository
2222
}
2323

2424
func fetch{{cookiecutter.domain_model}}s() -> AnyPublisher<[{{cookiecutter.domain_model}}], Error> {
2525
repository.queryPublisherForAll()
2626
}
27-
28-
func fetch{{cookiecutter.domain_model}}(with id: Int) -> AnyPublisher<{{cookiecutter.domain_model}}, Error> {
29-
repository.queryPublisher(for: "id=\(id)")
30-
.flatMap { items -> Result<{{cookiecutter.domain_model}}, Error>.Publisher in
31-
guard !items.isEmpty else {
32-
return .init(CustomError.notFound)
33-
}
34-
return .init(items[0])
35-
}.eraseToAnyPublisher()
27+
28+
func fetch(withId id: Int) -> AnyPublisher<{{cookiecutter.domain_model}}, Error> {
29+
repository.queryPublisher(forId: id)
30+
.eraseToAnyPublisher()
3631
}
3732

38-
func search{{cookiecutter.domain_model}}(with name: String) -> AnyPublisher<[{{cookiecutter.domain_model}}], Error> {
39-
repository.queryPublisher(for: "name=\(name)")
40-
.flatMap { items -> Result<[{{cookiecutter.domain_model}}], Error>.Publisher in
41-
guard !items.isEmpty else {
42-
return .init(CustomError.notFound)
43-
}
44-
return .init(items)
45-
}.eraseToAnyPublisher()
33+
func search(with query: String) -> AnyPublisher<[{{cookiecutter.domain_model}}], Error> {
34+
repository.queryPublisher(forQueryItems: [
35+
URLQueryItem(name: "query", value: query),
36+
// URLQueryItem(name: "page", value: "\(page)")
37+
])
38+
.flatMap { items -> Result<[{{cookiecutter.domain_model}}], Error>.Publisher in
39+
guard !items.isEmpty else {
40+
return .init(CustomError.notFound)
41+
}
42+
return .init(items)
43+
}.eraseToAnyPublisher()
4644
}
4745
}

{{cookiecutter.app_name}}/Platform/Repository/RemoteRepository.swift

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99
import Domain
1010
import Combine
1111

12-
class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
12+
class RemoteRepository<T: Codable>: RepositoryType, Combinable {
1313

1414
let network: Networking
1515

1616
private let baseURL: URL
17+
private let endpoint: Endpoint
1718
private let decoder: JSONDecoder = {
1819
let decoder = JSONDecoder()
1920
decoder.dateDecodingStrategy = .iso8601
@@ -23,22 +24,23 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
2324
return decoder
2425
}()
2526
private var endpointURL: URL {
26-
baseURL.appendingPathComponent(E.relativePath)
27+
baseURL.appendingPathComponent(endpoint.relativePath)
2728
}
2829

29-
public init(baseURL: URL, network: Networking) {
30+
init(baseURL: URL, network: Networking, endpoint: Endpoint) {
3031
self.baseURL = baseURL
3132
self.network = network
33+
self.endpoint = endpoint
3234
}
3335

34-
func queryAll(_ completion: @escaping (Result<[E.Resource], Error>) -> Void) {
36+
func queryAll(_ completion: @escaping (Result<[T], Error>) -> Void) {
3537
let request = URLRequest(url: self.endpointURL)
3638
network.send(request) { result in
3739
switch result {
3840
case .success(let data):
3941
do {
40-
let list = try self.decoder.decode(List<E.Resource>.self, from: data)
41-
completion(.success(list.results))
42+
let list = try self.decoder.decode([T].self, from: data)
43+
completion(.success(list))
4244
} catch let error {
4345
completion(.failure(error)) // DecodingError
4446
}
@@ -48,13 +50,30 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
4850
}
4951
}
5052

51-
func query(with queryString: String, completion: @escaping (Result<[E.Resource], Error>) -> Void) {
52-
guard var urlComponents = URLComponents(string: baseURL.absoluteString) else {
53+
func query(withId id: Int, completion: @escaping (Result<T, Error>) -> Void) {
54+
let url = self.endpointURL.appendingPathComponent("\(id)")
55+
let request = URLRequest(url: url)
56+
network.send(request) { result in
57+
switch result {
58+
case .success(let data):
59+
do {
60+
let item = try self.decoder.decode(T.self, from: data)
61+
completion(.success(item))
62+
} catch let error {
63+
completion(.failure(error)) // DecodingError
64+
}
65+
case .failure(let error):
66+
completion(.failure(error)) // NetworkError
67+
}
68+
}
69+
}
70+
71+
func query(withQueryItems queryItems: [URLQueryItem], completion: @escaping (Result<[T], Error>) -> Void) {
72+
guard var urlComponents = URLComponents(url: endpointURL, resolvingAgainstBaseURL: false) else {
5373
return completion(.failure(URLError(.badURL)))
5474
}
5575

56-
urlComponents.path = E.relativePath
57-
urlComponents.query = queryString
76+
urlComponents.queryItems?.append(contentsOf: queryItems)
5877

5978
guard let url = urlComponents.url else {
6079
return completion(.failure(URLError(.badURL)))
@@ -65,7 +84,7 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
6584
switch result {
6685
case .success(let data):
6786
do {
68-
let list = try self.decoder.decode(List<E.Resource>.self, from: data)
87+
let list = try self.decoder.decode(List<T>.self, from: data)
6988
completion(.success(list.results))
7089
} catch let error {
7190
completion(.failure(error)) // DecodingError
@@ -76,10 +95,10 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
7695
}
7796
}
7897

79-
func save(entity: E.Resource, completion: @escaping (Error?) -> Void) {
80-
let url = baseURL.appendingPathComponent(E.relativePath)
98+
func save(entity: T, completion: @escaping (Error?) -> Void) {
99+
let url = baseURL.appendingPathComponent(endpoint.relativePath)
81100
var request = URLRequest(url: url)
82-
request.httpMethod = E.method.rawValue
101+
request.httpMethod = HTTPMethod.post.rawValue // TODO: What about update PATCH?
83102
request.httpBody = try? JSONEncoder().encode(entity)
84103
self.network.send(request) { result in
85104
switch result {
@@ -99,8 +118,8 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
99118
}
100119
}
101120

102-
func delete(entity: E.Resource, completion: @escaping (Error?) -> Void) {
103-
let url = baseURL.appendingPathComponent(E.relativePath)
121+
func delete(entity: T, completion: @escaping (Error?) -> Void) {
122+
let url = baseURL.appendingPathComponent(endpoint.relativePath)
104123
let request = URLRequest(url: url)
105124
self.network.send(request) { result in
106125
switch result {
@@ -125,3 +144,19 @@ private struct List<T: Decodable>: Decodable {
125144
let totalPages: Int
126145
let results: [T]
127146
}
147+
148+
private extension URL {
149+
150+
func queryItemAdded(name: String, value: String?) -> URL? {
151+
return self.queryItemsAdded([URLQueryItem(name: name, value: value)])
152+
}
153+
154+
func queryItemsAdded(_ queryItems: [URLQueryItem]) -> URL? {
155+
guard var components = URLComponents(url: self, resolvingAgainstBaseURL: nil != self.baseURL) else {
156+
return nil
157+
}
158+
components.queryItems = queryItems + (components.queryItems ?? [])
159+
return components.url
160+
}
161+
162+
}

0 commit comments

Comments
 (0)