Skip to content

Commit

Permalink
fix: error building and added latest code
Browse files Browse the repository at this point in the history
  • Loading branch information
Aarif Sumra committed May 25, 2021
1 parent 229d88f commit 829e519
Show file tree
Hide file tree
Showing 38 changed files with 483 additions and 537 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@

import Foundation

public protocol {{cookiecutter.domain_model}}Entity: Entity {
// Required
var id: String { get }
var title: String { get }
// `Optional`s
var body: String? { get }
}

// Conformance to codable done here because it can not be done as extension. Proper place would be in the Platform module
public struct {{cookiecutter.domain_model}}: Codable {
// Required
public let id: Int
public let title: String
public let posterPath: String?
// Optionals
public private(set) var status: String?

public init(id: Int, title: String, posterPath: String?, status: String? = nil) {
self.id = id
self.title = title
self.posterPath = posterPath
self.status = status
}
// `Optional`s
public private(set) var body: String? = nil
}

extension {{cookiecutter.domain_model}}: Hashable {
Expand Down
13 changes: 13 additions & 0 deletions {{cookiecutter.app_name}}/Domain/Entity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// Entity.swift
// Domain
//
// Created by {{cookiecutter.lead_dev_name}} on {% now 'local' %}.
// Copyright © {% now 'local', '%Y' %} {{cookiecutter.company_name}} All rights reserved.
//

import Foundation

public protocol Entity {
var id: Int { get }
}
13 changes: 13 additions & 0 deletions {{cookiecutter.app_name}}/Domain/UseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//
// UseCase.swift
// Domain
//
// Created by {{cookiecutter.lead_dev_name}} on {% now 'local' %}.
// Copyright © {% now 'local', '%Y' %} {{cookiecutter.company_name}} All rights reserved.
//

import Foundation

public protocol UseCase {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// {{cookiecutter.domain_model}}sEndpoint.swift
// Platform
//
// Created by {{cookiecutter.lead_dev_name}} on {% now 'local' %}.
// Copyright © 2021 {{cookiecutter.company_name}} All rights reserved.
//

import Domain

enum Endpoints: Endpoint {
case {{cookiecutter.domain_model|lower}}s

var relativePath: String {
switch self {
case .{{cookiecutter.domain_model|lower}}s:
return "{{cookiecutter.domain_model|lower}}s"
}
}

var headers: [String : String] {
return [
"Content-Type": "application/json"
]
}
}

This file was deleted.

4 changes: 4 additions & 0 deletions {{cookiecutter.app_name}}/Platform/Network/Network.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public class Network: Networking {
public init(session: URLSession) {
self.session = session
}

static let `default` = {
Network(session: URLSession.shared)
}()

public func send(_ request: URLRequest, completion: @escaping (Result<Data, NetworkingError>) -> Void) {
let task = session.dataTask(with: request) { data, response, error in
Expand Down
6 changes: 2 additions & 4 deletions {{cookiecutter.app_name}}/Platform/Protocols/Endpoint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
import Domain

protocol Endpoint {
associatedtype Resource: Codable
static var method: HTTPMethod { get }
static var relativePath: String { get }
static var headers: [String: String] { get }
var relativePath: String { get }
var headers: [String: String] { get }
}
19 changes: 14 additions & 5 deletions {{cookiecutter.app_name}}/Platform/Protocols/RepositoryType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@
import Domain
import Combine

public enum RepositoryError: Error {
enum RepositoryError: Error {
case queryFailed(Error)
case saveFailed
case deleteFailed
}

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

func queryPublisher(for queryString: String) -> AnyPublisher<[T], Error> {
func queryPublisher(forId id: Int) -> AnyPublisher<T, Error> {
Future { promise in
self.query(with: queryString) { result in
self.query(withId: id) { result in
promise(result)
}
}.eraseToAnyPublisher()
}

func queryPublisher(forQueryItems queryItems: [URLQueryItem]) -> AnyPublisher<[T], Error> {
Future { promise in
self.query(withQueryItems: queryItems) { result in
promise(result)
}
}.eraseToAnyPublisher()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,31 @@ final class {{cookiecutter.domain_model}}sRepository {
case notFound
}

private let repository: RemoteRepository<{{cookiecutter.domain_model}}sEndpoint>
private let repository: RemoteRepository<{{cookiecutter.domain_model}}>

init(repository: RemoteRepository<{{cookiecutter.domain_model}}sEndpoint>) {
init(repository: RemoteRepository<{{cookiecutter.domain_model}}>) {
self.repository = repository
}

func fetch{{cookiecutter.domain_model}}s() -> AnyPublisher<[{{cookiecutter.domain_model}}], Error> {
repository.queryPublisherForAll()
}

func fetch{{cookiecutter.domain_model}}(with id: Int) -> AnyPublisher<{{cookiecutter.domain_model}}, Error> {
repository.queryPublisher(for: "id=\(id)")
.flatMap { items -> Result<{{cookiecutter.domain_model}}, Error>.Publisher in
guard !items.isEmpty else {
return .init(CustomError.notFound)
}
return .init(items[0])
}.eraseToAnyPublisher()

func fetch(withId id: Int) -> AnyPublisher<{{cookiecutter.domain_model}}, Error> {
repository.queryPublisher(forId: id)
.eraseToAnyPublisher()
}

func search{{cookiecutter.domain_model}}(with name: String) -> AnyPublisher<[{{cookiecutter.domain_model}}], Error> {
repository.queryPublisher(for: "name=\(name)")
.flatMap { items -> Result<[{{cookiecutter.domain_model}}], Error>.Publisher in
guard !items.isEmpty else {
return .init(CustomError.notFound)
}
return .init(items)
}.eraseToAnyPublisher()
func search(with query: String) -> AnyPublisher<[{{cookiecutter.domain_model}}], Error> {
repository.queryPublisher(forQueryItems: [
URLQueryItem(name: "query", value: query),
// URLQueryItem(name: "page", value: "\(page)")
])
.flatMap { items -> Result<[{{cookiecutter.domain_model}}], Error>.Publisher in
guard !items.isEmpty else {
return .init(CustomError.notFound)
}
return .init(items)
}.eraseToAnyPublisher()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
import Domain
import Combine

class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
class RemoteRepository<T: Codable>: RepositoryType, Combinable {

let network: Networking

private let baseURL: URL
private let endpoint: Endpoint
private let decoder: JSONDecoder = {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
Expand All @@ -23,22 +24,23 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
return decoder
}()
private var endpointURL: URL {
baseURL.appendingPathComponent(E.relativePath)
baseURL.appendingPathComponent(endpoint.relativePath)
}

public init(baseURL: URL, network: Networking) {
init(baseURL: URL, network: Networking, endpoint: Endpoint) {
self.baseURL = baseURL
self.network = network
self.endpoint = endpoint
}

func queryAll(_ completion: @escaping (Result<[E.Resource], Error>) -> Void) {
func queryAll(_ completion: @escaping (Result<[T], Error>) -> Void) {
let request = URLRequest(url: self.endpointURL)
network.send(request) { result in
switch result {
case .success(let data):
do {
let list = try self.decoder.decode(List<E.Resource>.self, from: data)
completion(.success(list.results))
let list = try self.decoder.decode([T].self, from: data)
completion(.success(list))
} catch let error {
completion(.failure(error)) // DecodingError
}
Expand All @@ -48,13 +50,30 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
}
}

func query(with queryString: String, completion: @escaping (Result<[E.Resource], Error>) -> Void) {
guard var urlComponents = URLComponents(string: baseURL.absoluteString) else {
func query(withId id: Int, completion: @escaping (Result<T, Error>) -> Void) {
let url = self.endpointURL.appendingPathComponent("\(id)")
let request = URLRequest(url: url)
network.send(request) { result in
switch result {
case .success(let data):
do {
let item = try self.decoder.decode(T.self, from: data)
completion(.success(item))
} catch let error {
completion(.failure(error)) // DecodingError
}
case .failure(let error):
completion(.failure(error)) // NetworkError
}
}
}

func query(withQueryItems queryItems: [URLQueryItem], completion: @escaping (Result<[T], Error>) -> Void) {
guard var urlComponents = URLComponents(url: endpointURL, resolvingAgainstBaseURL: false) else {
return completion(.failure(URLError(.badURL)))
}

urlComponents.path = E.relativePath
urlComponents.query = queryString
urlComponents.queryItems?.append(contentsOf: queryItems)

guard let url = urlComponents.url else {
return completion(.failure(URLError(.badURL)))
Expand All @@ -65,7 +84,7 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
switch result {
case .success(let data):
do {
let list = try self.decoder.decode(List<E.Resource>.self, from: data)
let list = try self.decoder.decode(List<T>.self, from: data)
completion(.success(list.results))
} catch let error {
completion(.failure(error)) // DecodingError
Expand All @@ -76,10 +95,10 @@ class RemoteRepository<E: Endpoint>: RepositoryType, Combinable {
}
}

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

func delete(entity: E.Resource, completion: @escaping (Error?) -> Void) {
let url = baseURL.appendingPathComponent(E.relativePath)
func delete(entity: T, completion: @escaping (Error?) -> Void) {
let url = baseURL.appendingPathComponent(endpoint.relativePath)
let request = URLRequest(url: url)
self.network.send(request) { result in
switch result {
Expand All @@ -125,3 +144,19 @@ private struct List<T: Decodable>: Decodable {
let totalPages: Int
let results: [T]
}

private extension URL {

func queryItemAdded(name: String, value: String?) -> URL? {
return self.queryItemsAdded([URLQueryItem(name: name, value: value)])
}

func queryItemsAdded(_ queryItems: [URLQueryItem]) -> URL? {
guard var components = URLComponents(url: self, resolvingAgainstBaseURL: nil != self.baseURL) else {
return nil
}
components.queryItems = queryItems + (components.queryItems ?? [])
return components.url
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ final class RepositoryProvider {
{{cookiecutter.domain_model}}sRepository(
repository: .init(
baseURL: baseURL,
network: network
network: network,
endpoint: Endpoints.{{cookiecutter.domain_model|lower}}s
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ public final class UseCaseProvider: Domain.UseCaseProvider {
}

public func make{{cookiecutter.domain_model}}sUseCase() -> Domain.{{cookiecutter.domain_model}}sUseCase {
let repo = repositoryProvider.make{{cookiecutter.domain_model}}sRepository()
return {{cookiecutter.domain_model}}sUseCase(repository: repo)
{{cookiecutter.domain_model}}sUseCase(
repository: repositoryProvider.makePostsRepository()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ final class {{cookiecutter.domain_model}}sUseCase: Domain.{{cookiecutter.domain_
}

func fetch(with id: Int) -> AnyPublisher<{{cookiecutter.domain_model}}, Error> {
repository.fetch{{cookiecutter.domain_model}}(with: id)
repository.fetch(withId: id)
}

func search(with name: String) -> AnyPublisher<[{{cookiecutter.domain_model}}], Error> {
repository.search{{cookiecutter.domain_model}}(with: name)
repository.search(with: name)
}
}
4 changes: 3 additions & 1 deletion {{cookiecutter.app_name}}/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ target '{{cookiecutter.app_name}}' do
pod 'NStackSDK', '~> 5.0'

# External
pod 'Kingfisher', '~> 6.0'
# pod 'Kingfisher', '~> 6.0'
pod 'CombineCocoa'
pod 'CombineExt'

post_install do |installer|
installer.pods_project.targets.each do |target|
Expand Down
Loading

0 comments on commit 829e519

Please sign in to comment.