diff --git a/Sources/Async/Worker.swift b/Sources/Async/Worker.swift index 1888d54c..77d707b1 100644 --- a/Sources/Async/Worker.swift +++ b/Sources/Async/Worker.swift @@ -41,6 +41,28 @@ extension Worker { public var eventLoop: EventLoop { return next() } + + /// Creates a new, succeeded `Future` from the worker's event loop. + /// + /// let a: Future = req.future("hello") + /// + /// - parameters: + /// - value: The value that the future will wrap. + /// - returns: The succeeded future. + func future(_ value: T) -> Future { + return self.eventLoop.newSucceededFuture(result: value) + } + + /// Creates a new, failed `Future` from the worker's event loop. + /// + /// let b: Future = req.future(error: Abort(...)) + /// + /// - parameters: + /// - error: The error that the future will wrap. + /// - returns: The failed future. + func future(error: Error) -> Future { + return self.eventLoop.newFailedFuture(error: error) + } } /// A basic `Worker` type that has a single `EventLoop`. diff --git a/Sources/Core/Reflectable.swift b/Sources/Core/Reflectable.swift index 7b3d919e..744d36ce 100644 --- a/Sources/Core/Reflectable.swift +++ b/Sources/Core/Reflectable.swift @@ -101,9 +101,10 @@ public protocol AnyReflectable { /// try User.reflectProperties(depth: 0) // [id: UUID?, name: String, pet: Pet] /// try User.reflectProperties(depth: 1) // [pet.name: String, pet.age: Int] /// - /// - parameters: depth: The level of nesting to use. - /// If `0`, the top-most properties will be returned. - /// If `1`, the first layer of nested properties, and so-on. + /// - parameters: + /// - depth: The level of nesting to use. + /// If `0`, the top-most properties will be returned. + /// If `1`, the first layer of nested properties, and so-on. /// - throws: Any error reflecting this type's properties. /// - returns: All `ReflectedProperty`s at the specified depth. static func reflectProperties(depth: Int) throws -> [ReflectedProperty] @@ -158,6 +159,13 @@ public struct ReflectedProperty { } } +extension Collection where Element == ReflectedProperty { + /// Removes all optional properties from an array of `ReflectedProperty`. + public func optionalsRemoved() -> [ReflectedProperty] { + return filter { !($0.type is AnyOptionalType.Type) } + } +} + extension ReflectedProperty: CustomStringConvertible { /// See `CustomStringConvertible.description` public var description: String { diff --git a/Tests/CoreTests/ReflectableTests.swift b/Tests/CoreTests/ReflectableTests.swift index ae586ef7..cd0fed0e 100644 --- a/Tests/CoreTests/ReflectableTests.swift +++ b/Tests/CoreTests/ReflectableTests.swift @@ -52,6 +52,27 @@ class ReflectableTests: XCTestCase { try XCTAssert(Foo.reflectProperty(forKey: \.odir)?.type is Direction?.Type) } + func testNonOptionalsOnly() throws { + struct Foo: Reflectable, Decodable { + var bool: Bool + var obool: Bool? + var int: Int + var oint: Int? + var sarr: [String] + var osarr: [String]? + } + + let properties = try Foo.reflectProperties().optionalsRemoved() + XCTAssertEqual(properties.description, "[bool: Bool, int: Int, sarr: Array]") + + try XCTAssertEqual(Foo.reflectProperty(forKey: \.bool)?.path, ["bool"]) + try XCTAssert(Foo.reflectProperty(forKey: \.bool)?.type is Bool.Type) + try XCTAssertEqual(Foo.reflectProperty(forKey: \.int)?.path, ["int"]) + try XCTAssert(Foo.reflectProperty(forKey: \.int)?.type is Int.Type) + try XCTAssertEqual(Foo.reflectProperty(forKey: \.sarr)?.path, ["sarr"]) + try XCTAssert(Foo.reflectProperty(forKey: \.sarr)?.type is [String].Type) + } + func testStructCustomProperties() throws { struct User: Reflectable { var firstName: String @@ -265,6 +286,7 @@ class ReflectableTests: XCTestCase { static let allTests = [ ("testStruct", testStruct), + ("testNonOptionalsOnly", testNonOptionalsOnly), ("testStructCustomProperties", testStructCustomProperties), ("testNestedStruct", testNestedStruct), ("testProperties", testProperties),