From c71d89c58b76f55de907de7f9767ef929a5bdb90 Mon Sep 17 00:00:00 2001 From: tanner0101 Date: Fri, 20 Mar 2020 19:04:21 -0400 Subject: [PATCH 1/7] void authenticator updates --- Package.swift | 2 +- Sources/Fluent/Deprecated.swift | 19 ++++++++++++++ Sources/Fluent/Fluent+Sessions.swift | 21 ++++++++------- ...lUser.swift => ModelAuthenticatable.swift} | 20 +++++++------- ....swift => ModelTokenAuthenticatable.swift} | 26 ++++++++++--------- Tests/FluentTests/FluentRepositoryTests.swift | 10 ++++--- 6 files changed, 63 insertions(+), 35 deletions(-) create mode 100644 Sources/Fluent/Deprecated.swift rename Sources/Fluent/{ModelUser.swift => ModelAuthenticatable.swift} (70%) rename Sources/Fluent/{ModelUserToken.swift => ModelTokenAuthenticatable.swift} (59%) diff --git a/Package.swift b/Package.swift index 0f9a3c75..390af5a8 100644 --- a/Package.swift +++ b/Package.swift @@ -11,7 +11,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/vapor/fluent-kit.git", from: "1.0.0-rc.1"), - .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0-rc.1"), + .package(url: "https://github.com/vapor/vapor.git", .branch("tn-authc-void")), ], targets: [ .target(name: "Fluent", dependencies: [ diff --git a/Sources/Fluent/Deprecated.swift b/Sources/Fluent/Deprecated.swift new file mode 100644 index 00000000..610b7246 --- /dev/null +++ b/Sources/Fluent/Deprecated.swift @@ -0,0 +1,19 @@ +import Vapor + +@available(*, deprecated, renamed: "ModelAuthenticatable") +public typealias ModelUser = ModelAuthenticatable + +@available(*, deprecated, renamed: "ModelAuthenticatable") +public typealias ModelUserToken = ModelTokenAuthenticatable + +extension Application.Fluent.Sessions { + @available(*, deprecated, renamed: "Model.sessionAuthenticator()") + public func middleware( + for user: User.Type, + databaseID: DatabaseID? = nil + ) -> Middleware + where User: SessionAuthenticatable, User: Model, User.SessionID == User.IDValue + { + User.sessionAuthenticator(databaseID: databaseID) + } +} diff --git a/Sources/Fluent/Fluent+Sessions.swift b/Sources/Fluent/Fluent+Sessions.swift index d5593d55..768e7f2f 100644 --- a/Sources/Fluent/Fluent+Sessions.swift +++ b/Sources/Fluent/Fluent+Sessions.swift @@ -10,16 +10,15 @@ extension Application.Fluent { } } -extension Application.Fluent.Sessions { - public func middleware( - for user: User.Type, +extension Model where Self: SessionAuthenticatable, Self.SessionID == Self.IDValue { + public static func sessionAuthenticator( databaseID: DatabaseID? = nil - ) -> Middleware - where User: SessionAuthenticatable, User: Model, User.SessionID == User.IDValue - { - DatabaseSessionAuthenticator(databaseID: databaseID).middleware() + ) -> Authenticator { + DatabaseSessionAuthenticator(databaseID: databaseID) } +} +extension Application.Fluent.Sessions { public func driver(_ databaseID: DatabaseID? = nil) -> SessionDriver { DatabaseSessions(databaseID: databaseID) } @@ -86,8 +85,12 @@ private struct DatabaseSessionAuthenticator: SessionAuthenticator { let databaseID: DatabaseID? - func resolve(sessionID: User.SessionID, for request: Request) -> EventLoopFuture { - User.find(sessionID, on: request.db) + func authenticate(sessionID: User.SessionID, for request: Request) -> EventLoopFuture { + User.find(sessionID, on: request.db).map { + if let user = $0 { + request.auth.login(user) + } + } } } diff --git a/Sources/Fluent/ModelUser.swift b/Sources/Fluent/ModelAuthenticatable.swift similarity index 70% rename from Sources/Fluent/ModelUser.swift rename to Sources/Fluent/ModelAuthenticatable.swift index 0479f4c2..5414db36 100644 --- a/Sources/Fluent/ModelUser.swift +++ b/Sources/Fluent/ModelAuthenticatable.swift @@ -1,16 +1,16 @@ import Vapor -public protocol ModelUser: Model, Authenticatable { +public protocol ModelAuthenticatable: Model, Authenticatable { static var usernameKey: KeyPath> { get } static var passwordHashKey: KeyPath> { get } func verify(password: String) throws -> Bool } -extension ModelUser { +extension ModelAuthenticatable { public static func authenticator( database: DatabaseID? = nil - ) -> ModelUserAuthenticator { - ModelUserAuthenticator(database: database) + ) -> Authenticator { + ModelAuthenticator(database: database) } var _$username: Field { @@ -22,27 +22,27 @@ extension ModelUser { } } -public struct ModelUserAuthenticator: BasicAuthenticator - where User: ModelUser +private struct ModelAuthenticator: BasicAuthenticator + where User: ModelAuthenticatable { public let database: DatabaseID? public func authenticate( basic: BasicAuthorization, for request: Request - ) -> EventLoopFuture { + ) -> EventLoopFuture { User.query(on: request.db(self.database)) .filter(\._$username == basic.username) .first() .flatMapThrowing { guard let user = $0 else { - return nil + return } guard try user.verify(password: basic.password) else { - return nil + return } - return user + request.auth.login(user) } } } diff --git a/Sources/Fluent/ModelUserToken.swift b/Sources/Fluent/ModelTokenAuthenticatable.swift similarity index 59% rename from Sources/Fluent/ModelUserToken.swift rename to Sources/Fluent/ModelTokenAuthenticatable.swift index a10748cd..df889dc1 100644 --- a/Sources/Fluent/ModelUserToken.swift +++ b/Sources/Fluent/ModelTokenAuthenticatable.swift @@ -1,17 +1,17 @@ import Vapor -public protocol ModelUserToken: Model { +public protocol ModelTokenAuthenticatable: Model, Authenticatable { associatedtype User: Model & Authenticatable static var valueKey: KeyPath> { get } static var userKey: KeyPath> { get } var isValid: Bool { get } } -extension ModelUserToken { +extension ModelTokenAuthenticatable { public static func authenticator( database: DatabaseID? = nil - ) -> ModelUserTokenAuthenticator { - ModelUserTokenAuthenticator(database: database) + ) -> Authenticator { + ModelTokenAuthenticator(database: database) } var _$value: Field { @@ -23,8 +23,8 @@ extension ModelUserToken { } } -public struct ModelUserTokenAuthenticator: BearerAuthenticator - where Token: ModelUserToken +private struct ModelTokenAuthenticator: BearerAuthenticator + where Token: ModelTokenAuthenticatable { public typealias User = Token.User public let database: DatabaseID? @@ -32,21 +32,23 @@ public struct ModelUserTokenAuthenticator: BearerAuthenticator public func authenticate( bearer: BearerAuthorization, for request: Request - ) -> EventLoopFuture { + ) -> EventLoopFuture { let db = request.db(self.database) return Token.query(on: db) .filter(\._$value == bearer.token) .first() .flatMap - { token -> EventLoopFuture in + { token -> EventLoopFuture in guard let token = token else { - return request.eventLoop.makeSucceededFuture(nil) + return request.eventLoop.makeSucceededFuture(()) } guard token.isValid else { - return token.delete(on: db).map { nil } + return token.delete(on: db) + } + request.auth.login(token) + return token._$user.get(on: db).map { + request.auth.login($0) } - return token._$user.get(on: db) - .map { $0 } } } } diff --git a/Tests/FluentTests/FluentRepositoryTests.swift b/Tests/FluentTests/FluentRepositoryTests.swift index b07b60dd..385e4f2a 100644 --- a/Tests/FluentTests/FluentRepositoryTests.swift +++ b/Tests/FluentTests/FluentRepositoryTests.swift @@ -78,18 +78,22 @@ private extension Request { } private extension Application { + private struct PostsKey: StorageKey { + typealias Value = PostRepositoryFactory + } + var posts: PostRepositoryFactory { get { - if let existing = self.userInfo["posts"] as? PostRepositoryFactory { + if let existing = self.storage[PostsKey.self] { return existing } else { let new = PostRepositoryFactory() - self.userInfo["posts"] = new + self.storage[PostsKey.self] = new return new } } set { - self.userInfo["posts"] = newValue + self.storage[PostsKey.self] = newValue } } } From 1fd38c565f4f78ed5122dc25adedef220b584439 Mon Sep 17 00:00:00 2001 From: tanner0101 Date: Fri, 3 Apr 2020 12:10:20 -0400 Subject: [PATCH 2/7] session migration updates --- Sources/Fluent/Fluent+Sessions.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/Fluent/Fluent+Sessions.swift b/Sources/Fluent/Fluent+Sessions.swift index d5593d55..2e05deb0 100644 --- a/Sources/Fluent/Fluent+Sessions.swift +++ b/Sources/Fluent/Fluent+Sessions.swift @@ -92,7 +92,11 @@ private struct DatabaseSessionAuthenticator: SessionAuthenticator } public final class Session: Model { - public static let schema = "sessions" + public static let schema = "_fluent_sessions" + + public static var migration: Migration { + CreateSession() + } @ID(key: "id") public var id: UUID? From c9771ea4165a10cf47363f26bd1748feac6d241d Mon Sep 17 00:00:00 2001 From: tanner0101 Date: Fri, 3 Apr 2020 18:52:28 -0400 Subject: [PATCH 3/7] session tests --- Package.swift | 5 +- ...peratorTests.swift => OperatorTests.swift} | 2 +- ...ationTests.swift => PaginationTests.swift} | 39 +++-- ...itoryTests.swift => RepositoryTests.swift} | 17 +- Tests/FluentTests/SessionTests.swift | 82 +++++++++ Tests/FluentTests/TestDatabase.swift | 162 +++++++++--------- 6 files changed, 199 insertions(+), 108 deletions(-) rename Tests/FluentTests/{FluentOperatorTests.swift => OperatorTests.swift} (97%) rename Tests/FluentTests/{FluentPaginationTests.swift => PaginationTests.swift} (80%) rename Tests/FluentTests/{FluentRepositoryTests.swift => RepositoryTests.swift} (90%) create mode 100644 Tests/FluentTests/SessionTests.swift diff --git a/Package.swift b/Package.swift index 390af5a8..f81b27ea 100644 --- a/Package.swift +++ b/Package.swift @@ -4,14 +4,14 @@ import PackageDescription let package = Package( name: "fluent", platforms: [ - .macOS(.v10_15) + .macOS(.v10_15), ], products: [ .library(name: "Fluent", targets: ["Fluent"]), ], dependencies: [ .package(url: "https://github.com/vapor/fluent-kit.git", from: "1.0.0-rc.1"), - .package(url: "https://github.com/vapor/vapor.git", .branch("tn-authc-void")), + .package(url: "https://github.com/vapor/vapor.git", .branch("gm")), ], targets: [ .target(name: "Fluent", dependencies: [ @@ -20,6 +20,7 @@ let package = Package( ]), .testTarget(name: "FluentTests", dependencies: [ .target(name: "Fluent"), + .product(name: "XCTFluent", package: "fluent-kit"), .product(name: "XCTVapor", package: "vapor"), ]), ] diff --git a/Tests/FluentTests/FluentOperatorTests.swift b/Tests/FluentTests/OperatorTests.swift similarity index 97% rename from Tests/FluentTests/FluentOperatorTests.swift rename to Tests/FluentTests/OperatorTests.swift index 068a71ee..518a5050 100644 --- a/Tests/FluentTests/FluentOperatorTests.swift +++ b/Tests/FluentTests/OperatorTests.swift @@ -2,7 +2,7 @@ import Fluent import Vapor import XCTVapor -final class FluentOperatorTests: XCTestCase { +final class OperatorTests: XCTestCase { func testCustomOperators() throws { let db = DummyDatabase() diff --git a/Tests/FluentTests/FluentPaginationTests.swift b/Tests/FluentTests/PaginationTests.swift similarity index 80% rename from Tests/FluentTests/FluentPaginationTests.swift rename to Tests/FluentTests/PaginationTests.swift index 63dbee37..fa362569 100644 --- a/Tests/FluentTests/FluentPaginationTests.swift +++ b/Tests/FluentTests/PaginationTests.swift @@ -1,36 +1,43 @@ import Fluent import Vapor import XCTVapor +import XCTFluent -final class FluentPaginationTests: XCTestCase { +final class PaginationTests: XCTestCase { func testPagination() throws { let app = Application(.testing) defer { app.shutdown() } - var rows: [TestRow] = [] + let test = TestDatabase() + app.databases.use(test.configuration, as: .test) + + app.get("todos") { req -> EventLoopFuture> in + Todo.query(on: req.db).paginate(for: req) + } + + var rows: [TestOutput] = [] for i in 1...1_000 { - rows.append(TestRow(data: ["id": i, "title": "Todo #\(i)"])) + rows.append(TestOutput([ + "id": i, + "title": "Todo #\(i)" + ])) } - - app.databases.use(TestDatabaseConfiguration { query in + + test.use { query in XCTAssertEqual(query.schema, "todos") - let result: [TestRow] + let result: [TestOutput] if let limit = query.limits.first?.value, let offset = query.offsets.first?.value { - result = [TestRow](rows[min(offset, rows.count - 1).. EventLoopFuture> in - Todo.query(on: req.db).paginate(for: req) } try app.test(.GET, "todos") { res in diff --git a/Tests/FluentTests/FluentRepositoryTests.swift b/Tests/FluentTests/RepositoryTests.swift similarity index 90% rename from Tests/FluentTests/FluentRepositoryTests.swift rename to Tests/FluentTests/RepositoryTests.swift index 45639e26..9484ac30 100644 --- a/Tests/FluentTests/FluentRepositoryTests.swift +++ b/Tests/FluentTests/RepositoryTests.swift @@ -1,8 +1,9 @@ import Fluent import Vapor +import XCTFluent import XCTVapor -final class FluentRepositoryTests: XCTestCase { +final class RepositoryTests: XCTestCase { func testRepositoryPatternStatic() throws { let app = Application(.testing) defer { app.shutdown() } @@ -37,13 +38,8 @@ final class FluentRepositoryTests: XCTestCase { let app = Application(.testing) defer { app.shutdown() } - app.databases.use(TestDatabaseConfiguration { query in - XCTAssertEqual(query.schema, "posts") - return [ - TestRow(data: ["id": 1, "content": "a"]), - TestRow(data: ["id": 2, "content": "b"]), - ] - }, as: .test) + let test = TestDatabase() + app.databases.use(test.configuration, as: .test) app.posts.use { req in DatabasePostRepository(database: req.db(.test)) @@ -57,6 +53,11 @@ final class FluentRepositoryTests: XCTestCase { .init(id: 1, content: "a"), .init(id: 2, content: "b") ] + + test.append([ + TestOutput(["id": 1, "content": "a"]), + TestOutput(["id": 2, "content": "b"]), + ]) try app.testable().test(.GET, "foo") { res in XCTAssertEqual(res.status, .ok) diff --git a/Tests/FluentTests/SessionTests.swift b/Tests/FluentTests/SessionTests.swift new file mode 100644 index 00000000..7ac16e2a --- /dev/null +++ b/Tests/FluentTests/SessionTests.swift @@ -0,0 +1,82 @@ +import XCTFluent +import XCTVapor +import Fluent + +final class SessionTests: XCTestCase { + func testSessions() throws { + let app = Application(.testing) + defer { app.shutdown() } + + // Setup test db. + let test = TestDatabase() + app.databases.use(test.configuration, as: .test) + + // Configure sessions. + app.sessions.use(.fluent) + app.middleware.use(app.sessions.middleware) + + // Setup routes. + app.get("set", ":value") { req -> HTTPStatus in + req.session.data["name"] = req.parameters.get("value") + return .ok + } + app.get("get") { req -> String in + req.session.data["name"] ?? "n/a" + } + app.get("del") { req -> HTTPStatus in + req.session.destroy() + return .ok + } + + // Add single query output with empty row. + test.append([TestOutput()]) + // Store session id. + var sessionID: String? + try app.test(.GET, "/set/vapor") { res in + sessionID = res.headers.setCookie?["vapor-session"]?.string + XCTAssertEqual(res.status, .ok) + } + + // Add single query output with session data for session read. + test.append([ + TestOutput([ + "id": UUID(), + "key": SessionID(string: sessionID!), + "data": SessionData(["name": "vapor"]) + ]) + ]) + // Add empty query output for session update. + test.append([]) + try app.test(.GET, "/get", beforeRequest: { req in + var cookies = HTTPCookies() + cookies["vapor-session"] = .init(string: sessionID!) + req.headers.cookie = cookies + }) { res in + XCTAssertEqual(res.status, .ok) + XCTAssertEqual(res.body.string, "vapor") + } + } +} + +extension DatabaseID { + static var test: Self { + .init(string: "test") + } +} + +struct StaticDatabase: DatabaseConfiguration, DatabaseDriver { + let database: Database + var middleware: [AnyModelMiddleware] = [] + + func makeDriver(for databases: Databases) -> DatabaseDriver { + self + } + + func makeDatabase(with context: DatabaseContext) -> Database { + self.database + } + + func shutdown() { + // Do nothing. + } +} diff --git a/Tests/FluentTests/TestDatabase.swift b/Tests/FluentTests/TestDatabase.swift index b14ead33..bcb3d05f 100644 --- a/Tests/FluentTests/TestDatabase.swift +++ b/Tests/FluentTests/TestDatabase.swift @@ -1,81 +1,81 @@ -import Fluent - -extension DatabaseID { - static var test: DatabaseID { .init(string: "test") } -} - -struct TestDatabase: Database { - let driver: TestDatabaseDriver - let context: DatabaseContext - - func execute(query: DatabaseQuery, onOutput: @escaping (DatabaseOutput) -> ()) -> EventLoopFuture { - self.driver.handler(query).forEach { row in - self.context.eventLoop.execute { - onOutput(row) - } - } - return self.eventLoop.makeSucceededFuture(()) - } - - func execute(schema: DatabaseSchema) -> EventLoopFuture { - fatalError() - } - - func execute(enum: DatabaseEnum) -> EventLoopFuture { - fatalError() - } - - func withConnection(_ closure: @escaping (Database) -> EventLoopFuture) -> EventLoopFuture { - closure(self) - } - - func transaction(_ closure: @escaping (Database) -> EventLoopFuture) -> EventLoopFuture { - closure(self) - } -} - -struct TestRow: DatabaseOutput { - var data: [FieldKey: Any] - - var description: String { - self.data.description - } - - func schema(_ schema: String) -> DatabaseOutput { - self - } - - func contains(_ path: [FieldKey]) -> Bool { - self.data.keys.contains(path[0]) - } - - func decode(_ path: [FieldKey], as type: T.Type) throws -> T where T : Decodable { - self.data[path[0]]! as! T - } -} - -final class TestDatabaseDriver: DatabaseDriver { - let handler: (DatabaseQuery) -> [DatabaseOutput] - - init(_ handler: @escaping (DatabaseQuery) -> [DatabaseOutput]) { - self.handler = handler - } - - func makeDatabase(with context: DatabaseContext) -> Database { - TestDatabase(driver: self, context: context) - } - - func shutdown() { - // nothing - } -} - -struct TestDatabaseConfiguration: DatabaseConfiguration { - let handler: (DatabaseQuery) -> [DatabaseOutput] - - var middleware: [AnyModelMiddleware] = [] - - func makeDriver(for databases: Databases) -> DatabaseDriver { - TestDatabaseDriver(handler) - } -} +//import Fluent +// +//extension DatabaseID { +// static var test: DatabaseID { .init(string: "test") } +//} +// +//struct TestDatabase: Database { +// let driver: TestDatabaseDriver +// let context: DatabaseContext +// +// func execute(query: DatabaseQuery, onOutput: @escaping (DatabaseOutput) -> ()) -> EventLoopFuture { +// self.driver.handler(query).forEach { row in +// self.context.eventLoop.execute { +// onOutput(row) +// } +// } +// return self.eventLoop.makeSucceededFuture(()) +// } +// +// func execute(schema: DatabaseSchema) -> EventLoopFuture { +// fatalError() +// } +// +// func execute(enum: DatabaseEnum) -> EventLoopFuture { +// fatalError() +// } +// +// func withConnection(_ closure: @escaping (Database) -> EventLoopFuture) -> EventLoopFuture { +// closure(self) +// } +// +// func transaction(_ closure: @escaping (Database) -> EventLoopFuture) -> EventLoopFuture { +// closure(self) +// } +//} +// +//struct TestRow: DatabaseOutput { +// var data: [FieldKey: Any] +// +// var description: String { +// self.data.description +// } +// +// func schema(_ schema: String) -> DatabaseOutput { +// self +// } +// +// func contains(_ path: [FieldKey]) -> Bool { +// self.data.keys.contains(path[0]) +// } +// +// func decode(_ path: [FieldKey], as type: T.Type) throws -> T where T : Decodable { +// self.data[path[0]]! as! T +// } +//} +// +//final class TestDatabaseDriver: DatabaseDriver { +// let handler: (DatabaseQuery) -> [DatabaseOutput] +// +// init(_ handler: @escaping (DatabaseQuery) -> [DatabaseOutput]) { +// self.handler = handler +// } +// +// func makeDatabase(with context: DatabaseContext) -> Database { +// TestDatabase(driver: self, context: context) +// } +// +// func shutdown() { +// // nothing +// } +//} +// +//struct TestDatabaseConfiguration: DatabaseConfiguration { +// let handler: (DatabaseQuery) -> [DatabaseOutput] +// +// var middleware: [AnyModelMiddleware] = [] +// +// func makeDriver(for databases: Databases) -> DatabaseDriver { +// TestDatabaseDriver(handler) +// } +//} From 22a79a488cd5451c2373d7997ae0094d1d2e23b1 Mon Sep 17 00:00:00 2001 From: tanner0101 Date: Thu, 9 Apr 2020 13:27:23 -0400 Subject: [PATCH 4/7] updates --- Sources/Fluent/Deprecated.swift | 2 +- Sources/Fluent/Fluent+Sessions.swift | 61 +++++++++++++++---------- Tests/FluentTests/PaginationTests.swift | 15 +++--- Tests/FluentTests/RepositoryTests.swift | 2 +- Tests/FluentTests/SessionTests.swift | 23 +++++++++- 5 files changed, 66 insertions(+), 37 deletions(-) diff --git a/Sources/Fluent/Deprecated.swift b/Sources/Fluent/Deprecated.swift index 610b7246..30c7069a 100644 --- a/Sources/Fluent/Deprecated.swift +++ b/Sources/Fluent/Deprecated.swift @@ -14,6 +14,6 @@ extension Application.Fluent.Sessions { ) -> Middleware where User: SessionAuthenticatable, User: Model, User.SessionID == User.IDValue { - User.sessionAuthenticator(databaseID: databaseID) + User.sessionAuthenticator(databaseID) } } diff --git a/Sources/Fluent/Fluent+Sessions.swift b/Sources/Fluent/Fluent+Sessions.swift index 2ea5b096..d8021257 100644 --- a/Sources/Fluent/Fluent+Sessions.swift +++ b/Sources/Fluent/Fluent+Sessions.swift @@ -10,9 +10,22 @@ extension Application.Fluent { } } +public protocol ModelSessionAuthenticatable: Model, SessionAuthenticatable + where Self.SessionID == Self.IDValue +{ } + +extension ModelSessionAuthenticatable { + public var sessionID: SessionID { + guard let id = self.id else { + fatalError("Cannot persist unsaved model to session.") + } + return id + } +} + extension Model where Self: SessionAuthenticatable, Self.SessionID == Self.IDValue { public static func sessionAuthenticator( - databaseID: DatabaseID? = nil + _ databaseID: DatabaseID? = nil ) -> Authenticator { DatabaseSessionAuthenticator(databaseID: databaseID) } @@ -45,20 +58,20 @@ private struct DatabaseSessions: SessionDriver { func createSession(_ data: SessionData, for request: Request) -> EventLoopFuture { let id = self.generateID() - return Session(key: id, data: data) + return SessionRecord(key: id, data: data) .create(on: request.db(self.databaseID)) .map { id } } func readSession(_ sessionID: SessionID, for request: Request) -> EventLoopFuture { - return Session.query(on: request.db(self.databaseID)) + SessionRecord.query(on: request.db(self.databaseID)) .filter(\.$key == sessionID) .first() .map { $0?.data } } func updateSession(_ sessionID: SessionID, to data: SessionData, for request: Request) -> EventLoopFuture { - return Session.query(on: request.db(self.databaseID)) + SessionRecord.query(on: request.db(self.databaseID)) .filter(\.$key == sessionID) .set(\.$data, to: data) .update() @@ -66,7 +79,7 @@ private struct DatabaseSessions: SessionDriver { } func deleteSession(_ sessionID: SessionID, for request: Request) -> EventLoopFuture { - return Session.query(on: request.db(self.databaseID)) + SessionRecord.query(on: request.db(self.databaseID)) .filter(\.$key == sessionID) .delete() } @@ -94,14 +107,28 @@ private struct DatabaseSessionAuthenticator: SessionAuthenticator } } -public final class Session: Model { +public final class SessionRecord: Model { public static let schema = "_fluent_sessions" + private struct _Migration: Migration { + func prepare(on database: Database) -> EventLoopFuture { + database.schema("_fluent_sessions") + .id() + .field("key", .string, .required) + .field("data", .json, .required) + .create() + } + + func revert(on database: Database) -> EventLoopFuture { + database.schema("_fluent_sessions").delete() + } + } + public static var migration: Migration { - CreateSession() + _Migration() } - @ID(key: "id") + @ID(key: .id) public var id: UUID? @Field(key: "key") @@ -110,9 +137,7 @@ public final class Session: Model { @Field(key: "data") public var data: SessionData - public init() { - - } + public init() { } public init(id: UUID? = nil, key: SessionID, data: SessionData) { self.id = id @@ -120,17 +145,3 @@ public final class Session: Model { self.data = data } } - -public struct CreateSession: Migration { - public func prepare(on database: Database) -> EventLoopFuture { - return database.schema("sessions") - .field("id", .uuid, .identifier(auto: false)) - .field("key", .string, .required) - .field("data", .json, .required) - .create() - } - - public func revert(on database: Database) -> EventLoopFuture { - return database.schema("sessions").delete() - } -} diff --git a/Tests/FluentTests/PaginationTests.swift b/Tests/FluentTests/PaginationTests.swift index fa362569..07b3a897 100644 --- a/Tests/FluentTests/PaginationTests.swift +++ b/Tests/FluentTests/PaginationTests.swift @@ -8,13 +8,6 @@ final class PaginationTests: XCTestCase { let app = Application(.testing) defer { app.shutdown() } - let test = TestDatabase() - app.databases.use(test.configuration, as: .test) - - app.get("todos") { req -> EventLoopFuture> in - Todo.query(on: req.db).paginate(for: req) - } - var rows: [TestOutput] = [] for i in 1...1_000 { rows.append(TestOutput([ @@ -22,8 +15,7 @@ final class PaginationTests: XCTestCase { "title": "Todo #\(i)" ])) } - - test.use { query in + let test = CallbackTestDatabase { query in XCTAssertEqual(query.schema, "todos") let result: [TestOutput] if let limit = query.limits.first?.value, let offset = query.offsets.first?.value { @@ -39,6 +31,11 @@ final class PaginationTests: XCTestCase { return result } } + app.databases.use(test.configuration, as: .test) + + app.get("todos") { req -> EventLoopFuture> in + Todo.query(on: req.db).paginate(for: req) + } try app.test(.GET, "todos") { res in XCTAssertEqual(res.status, .ok) diff --git a/Tests/FluentTests/RepositoryTests.swift b/Tests/FluentTests/RepositoryTests.swift index 9484ac30..338f17c5 100644 --- a/Tests/FluentTests/RepositoryTests.swift +++ b/Tests/FluentTests/RepositoryTests.swift @@ -38,7 +38,7 @@ final class RepositoryTests: XCTestCase { let app = Application(.testing) defer { app.shutdown() } - let test = TestDatabase() + let test = ArrayTestDatabase() app.databases.use(test.configuration, as: .test) app.posts.use { req in diff --git a/Tests/FluentTests/SessionTests.swift b/Tests/FluentTests/SessionTests.swift index 7ac16e2a..a4753755 100644 --- a/Tests/FluentTests/SessionTests.swift +++ b/Tests/FluentTests/SessionTests.swift @@ -1,6 +1,7 @@ import XCTFluent import XCTVapor import Fluent +import Vapor final class SessionTests: XCTestCase { func testSessions() throws { @@ -8,8 +9,9 @@ final class SessionTests: XCTestCase { defer { app.shutdown() } // Setup test db. - let test = TestDatabase() + let test = ArrayTestDatabase() app.databases.use(test.configuration, as: .test) + app.migrations.add(SessionRecord.migration) // Configure sessions. app.sessions.use(.fluent) @@ -58,6 +60,25 @@ final class SessionTests: XCTestCase { } } +final class User: Model { + static let schema = "users" + + @ID(key: .id) + var id: UUID? + + @Field(key: "name") + var name: String + + init() { } + + init(id: UUID? = nil, name: String) { + self.id = id + self.name = name + } +} + +extension User: ModelSessionAuthenticatable { } + extension DatabaseID { static var test: Self { .init(string: "test") From 288e998497c2a1cdbc043cf624b4a8f292c9af23 Mon Sep 17 00:00:00 2001 From: tanner0101 Date: Thu, 9 Apr 2020 13:33:48 -0400 Subject: [PATCH 5/7] use fk branch --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index f81b27ea..4309e9a0 100644 --- a/Package.swift +++ b/Package.swift @@ -10,7 +10,7 @@ let package = Package( .library(name: "Fluent", targets: ["Fluent"]), ], dependencies: [ - .package(url: "https://github.com/vapor/fluent-kit.git", from: "1.0.0-rc.1"), + .package(url: "https://github.com/vapor/fluent-kit.git", .branch("vapor-gm")), .package(url: "https://github.com/vapor/vapor.git", .branch("gm")), ], targets: [ From 00879e81320b284e5e5c42572f7b0361c47bf2c4 Mon Sep 17 00:00:00 2001 From: tanner0101 Date: Thu, 9 Apr 2020 13:58:34 -0400 Subject: [PATCH 6/7] update tags --- Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index 4309e9a0..6475730b 100644 --- a/Package.swift +++ b/Package.swift @@ -10,8 +10,8 @@ let package = Package( .library(name: "Fluent", targets: ["Fluent"]), ], dependencies: [ - .package(url: "https://github.com/vapor/fluent-kit.git", .branch("vapor-gm")), - .package(url: "https://github.com/vapor/vapor.git", .branch("gm")), + .package(url: "https://github.com/vapor/fluent-kit.git", from: "1.0.0-rc.1.19"), + .package(url: "https://github.com/vapor/vapor.git", from: "4.0.0"), ], targets: [ .target(name: "Fluent", dependencies: [ From 6ebd0079295bf639e895d35b2a540ae3c528bfc6 Mon Sep 17 00:00:00 2001 From: tanner0101 Date: Thu, 9 Apr 2020 14:08:08 -0400 Subject: [PATCH 7/7] rm old test db --- Tests/FluentTests/TestDatabase.swift | 81 ---------------------------- 1 file changed, 81 deletions(-) delete mode 100644 Tests/FluentTests/TestDatabase.swift diff --git a/Tests/FluentTests/TestDatabase.swift b/Tests/FluentTests/TestDatabase.swift deleted file mode 100644 index bcb3d05f..00000000 --- a/Tests/FluentTests/TestDatabase.swift +++ /dev/null @@ -1,81 +0,0 @@ -//import Fluent -// -//extension DatabaseID { -// static var test: DatabaseID { .init(string: "test") } -//} -// -//struct TestDatabase: Database { -// let driver: TestDatabaseDriver -// let context: DatabaseContext -// -// func execute(query: DatabaseQuery, onOutput: @escaping (DatabaseOutput) -> ()) -> EventLoopFuture { -// self.driver.handler(query).forEach { row in -// self.context.eventLoop.execute { -// onOutput(row) -// } -// } -// return self.eventLoop.makeSucceededFuture(()) -// } -// -// func execute(schema: DatabaseSchema) -> EventLoopFuture { -// fatalError() -// } -// -// func execute(enum: DatabaseEnum) -> EventLoopFuture { -// fatalError() -// } -// -// func withConnection(_ closure: @escaping (Database) -> EventLoopFuture) -> EventLoopFuture { -// closure(self) -// } -// -// func transaction(_ closure: @escaping (Database) -> EventLoopFuture) -> EventLoopFuture { -// closure(self) -// } -//} -// -//struct TestRow: DatabaseOutput { -// var data: [FieldKey: Any] -// -// var description: String { -// self.data.description -// } -// -// func schema(_ schema: String) -> DatabaseOutput { -// self -// } -// -// func contains(_ path: [FieldKey]) -> Bool { -// self.data.keys.contains(path[0]) -// } -// -// func decode(_ path: [FieldKey], as type: T.Type) throws -> T where T : Decodable { -// self.data[path[0]]! as! T -// } -//} -// -//final class TestDatabaseDriver: DatabaseDriver { -// let handler: (DatabaseQuery) -> [DatabaseOutput] -// -// init(_ handler: @escaping (DatabaseQuery) -> [DatabaseOutput]) { -// self.handler = handler -// } -// -// func makeDatabase(with context: DatabaseContext) -> Database { -// TestDatabase(driver: self, context: context) -// } -// -// func shutdown() { -// // nothing -// } -//} -// -//struct TestDatabaseConfiguration: DatabaseConfiguration { -// let handler: (DatabaseQuery) -> [DatabaseOutput] -// -// var middleware: [AnyModelMiddleware] = [] -// -// func makeDriver(for databases: Databases) -> DatabaseDriver { -// TestDatabaseDriver(handler) -// } -//}