Created basic Respondable protocol structure
This commit is contained in:
commit
a1c5960fad
|
@ -0,0 +1,4 @@
|
|||
.DS_Store
|
||||
/.build
|
||||
/Packages
|
||||
/*.xcodeproj
|
|
@ -0,0 +1,160 @@
|
|||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "Console",
|
||||
"repositoryURL": "https://github.com/vapor/console.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "d6cf07af59ae63cd95c4b5f98cf1f25627750fd1",
|
||||
"version": "3.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Core",
|
||||
"repositoryURL": "https://github.com/vapor/core.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "1794ff138bd669175a2528d27695028d7cb30471",
|
||||
"version": "3.5.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Crypto",
|
||||
"repositoryURL": "https://github.com/vapor/crypto.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "bce9ac891c9b33fc045deda713e0d976d13b749a",
|
||||
"version": "3.3.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "DatabaseKit",
|
||||
"repositoryURL": "https://github.com/vapor/database-kit.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "3557894af50914e134803a684b42a9ea6eefaea2",
|
||||
"version": "1.3.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "HTTP",
|
||||
"repositoryURL": "https://github.com/vapor/http.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "4c8c655932fdb409c11549eadabf27d3d61bc24c",
|
||||
"version": "3.1.7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Multipart",
|
||||
"repositoryURL": "https://github.com/vapor/multipart.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "bd7736c5f28e48ed8b683dcc9df3dcd346064c2b",
|
||||
"version": "3.0.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Routing",
|
||||
"repositoryURL": "https://github.com/vapor/routing.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "3219e328491b0853b8554c5a694add344d2c6cfb",
|
||||
"version": "3.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Service",
|
||||
"repositoryURL": "https://github.com/vapor/service.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "281a70b69783891900be31a9e70051b6fe19e146",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "03c541a24dd0558c942b15d8464eb75d70a921c4",
|
||||
"version": "1.12.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-ssl",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-ssl.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "0f3999f3e3c359cc74480c292644c3419e44a12f",
|
||||
"version": "1.4.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-ssl-support",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-ssl-support.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "c02eec4e0e6d351cd092938cf44195a8e669f555",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "swift-nio-zlib-support",
|
||||
"repositoryURL": "https://github.com/apple/swift-nio-zlib-support.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "37760e9a52030bb9011972c5213c3350fa9d41fd",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "TemplateKit",
|
||||
"repositoryURL": "https://github.com/vapor/template-kit.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "aff2d6fc65bfd04579b0201b31a8d6720239c1cf",
|
||||
"version": "1.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "URLEncodedForm",
|
||||
"repositoryURL": "https://github.com/vapor/url-encoded-form.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "932024f363ee5ff59059cf7d67194a1c271d3d0c",
|
||||
"version": "1.0.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Validation",
|
||||
"repositoryURL": "https://github.com/vapor/validation.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "4de213cf319b694e4ce19e5339592601d4dd3ff6",
|
||||
"version": "2.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Vapor",
|
||||
"repositoryURL": "https://github.com/vapor/vapor.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "54cbf396147aba77ecb32e7fc75a3d13251551b1",
|
||||
"version": "3.1.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "WebSocket",
|
||||
"repositoryURL": "https://github.com/vapor/websocket.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "21eb4773e25a8ff96fe347a31fe106900a69fa6a",
|
||||
"version": "1.1.1"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"version": 1
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// swift-tools-version:4.2
|
||||
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "ModelResponse",
|
||||
products: [
|
||||
.library(name: "ModelResponse", targets: ["ModelResponse"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/vapor/vapor.git", from: "3.1.1")
|
||||
],
|
||||
targets: [
|
||||
.target(name: "ModelResponse", dependencies: ["Vapor"]),
|
||||
.testTarget(name: "ModelResponseTests", dependencies: ["ModelResponse"]),
|
||||
]
|
||||
)
|
|
@ -0,0 +1,41 @@
|
|||
import Vapor
|
||||
|
||||
public protocol Respondable {
|
||||
associatedtype Result: ResponseEncodable
|
||||
|
||||
func response(on container: Container) -> Future<Self.Result>
|
||||
}
|
||||
|
||||
extension Respondable where Self: ResponseEncodable {
|
||||
public func response(on container: Container) -> Future<Self> {
|
||||
return container.future(self)
|
||||
}
|
||||
}
|
||||
|
||||
extension Array: Respondable where Element: Respondable, Element.Result: Content {
|
||||
public typealias Result = [Element.Result]
|
||||
|
||||
public func response(on container: Container) -> Future<[Element.Result]> {
|
||||
return self.map { $0.response(on: container) }.flatten(on: container)
|
||||
}
|
||||
}
|
||||
|
||||
extension Dictionary: Respondable where Key == String, Value: Respondable, Value.Result: Content {
|
||||
public typealias Result = [String: Value.Result]
|
||||
|
||||
public func response(on container: Container) -> Future<[String: Value.Result]> {
|
||||
return self.map { key, value in value.response(on: container).and(result: key) }.flatten(on: container).map { list in
|
||||
return list.reduce(into: [:]) { result, pair in
|
||||
result[pair.1] = pair.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Future: Respondable where T: Respondable {
|
||||
public typealias Result = T.Result
|
||||
|
||||
public func response(on container: Container) -> EventLoopFuture<T.Result> {
|
||||
return self.flatMap { t in t.response(on: container) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import XCTest
|
||||
|
||||
import ModelResponseTests
|
||||
|
||||
var tests = [XCTestCaseEntry]()
|
||||
tests += ModelResponseTests.allTests()
|
||||
XCTMain(tests)
|
|
@ -0,0 +1,115 @@
|
|||
import XCTest
|
||||
import Vapor
|
||||
@testable import ModelResponse
|
||||
|
||||
final class ModelResponseTests: XCTestCase {
|
||||
var app: Application!
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
|
||||
self.app = try! Application(config: Config.default(), environment: Environment.detect(), services: Services.default())
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
self.app = nil
|
||||
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testUser()throws {
|
||||
let user = User(name: "Caleb", password: "bad-password", age: 42)
|
||||
let response = try user.response(on: self.app).wait()
|
||||
|
||||
XCTAssertEqual(response.age, 42)
|
||||
XCTAssertEqual(response.name, "Caleb")
|
||||
}
|
||||
|
||||
func testArray()throws {
|
||||
let users = [User(name: "Caleb", password: "bad-password", age: 42), User(name: "Tanner", password: "0101", age: 31)]
|
||||
let response = try users.response(on: self.app).wait()
|
||||
|
||||
XCTAssertEqual(response[0].age, 42)
|
||||
XCTAssertEqual(response[0].name, "Caleb")
|
||||
XCTAssertEqual(response[1].age, 31)
|
||||
XCTAssertEqual(response[1].name, "Tanner")
|
||||
}
|
||||
|
||||
func testDictionary()throws {
|
||||
let users = [
|
||||
"Caleb": User(name: "Caleb", password: "bad-password", age: 42),
|
||||
"Tanner": User(name: "Tanner", password: "0101", age: 31)
|
||||
]
|
||||
let response = try users.response(on: self.app).wait()
|
||||
|
||||
XCTAssertEqual(response["Caleb"]?.age, 42)
|
||||
XCTAssertEqual(response["Caleb"]?.name, "Caleb")
|
||||
XCTAssertEqual(response["Tanner"]?.age, 31)
|
||||
XCTAssertEqual(response["Tanner"]?.name, "Tanner")
|
||||
}
|
||||
|
||||
func testFuture()throws {
|
||||
let user = self.app.future(User(name: "Caleb", password: "bad-password", age: 42))
|
||||
let response = try user.response(on: self.app).wait()
|
||||
|
||||
XCTAssertEqual(response.age, 42)
|
||||
XCTAssertEqual(response.name, "Caleb")
|
||||
}
|
||||
|
||||
func testFutureArrayDictionary()throws {
|
||||
let user = self.app.future(["users": [User(name: "Caleb", password: "bad-password", age: 42)]])
|
||||
let response = try user.response(on: self.app).wait()
|
||||
|
||||
XCTAssertEqual(response["users"]?[0].age, 42)
|
||||
XCTAssertEqual(response["users"]?[0].name, "Caleb")
|
||||
}
|
||||
|
||||
func testDefault()throws {
|
||||
let token = Token(hash: "#AF0091")
|
||||
let response = try token.response(on: self.app).wait()
|
||||
|
||||
XCTAssertEqual(response.hash, "#AF0091")
|
||||
}
|
||||
|
||||
static var allTests = [
|
||||
("testUser", testUser),
|
||||
("testArray", testArray),
|
||||
("testDictionary", testDictionary),
|
||||
("testFuture", testFuture),
|
||||
("testFutureArrayDictionary", testFutureArrayDictionary),
|
||||
("testDefault", testDefault)
|
||||
]
|
||||
}
|
||||
|
||||
final class User {
|
||||
let password: String
|
||||
let name: String
|
||||
let age: Int
|
||||
|
||||
init(name: String, password: String, age: Int) {
|
||||
self.password = password
|
||||
self.name = name
|
||||
self.age = age
|
||||
}
|
||||
}
|
||||
|
||||
extension User: Respondable {
|
||||
struct Result: Content {
|
||||
let name: String
|
||||
let age: Int
|
||||
}
|
||||
|
||||
func response(on container: Container) -> EventLoopFuture<User.Result> {
|
||||
return container.future(User.Result(name: self.name, age: self.age))
|
||||
}
|
||||
}
|
||||
|
||||
final class Token: Content, Respondable {
|
||||
typealias Result = Token
|
||||
|
||||
let hash: String
|
||||
|
||||
init(hash: String) {
|
||||
self.hash = hash
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import XCTest
|
||||
|
||||
#if !os(macOS)
|
||||
public func allTests() -> [XCTestCaseEntry] {
|
||||
return [
|
||||
testCase(ModelResponseTests.allTests),
|
||||
]
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue