From 27f9ca6a4b12c1be9e1a8c097009b09687dd335c Mon Sep 17 00:00:00 2001 From: twof Date: Fri, 28 Sep 2018 18:04:55 -0700 Subject: [PATCH] initial commit --- .gitignore | 4 + Package.resolved | 178 ++++++++++++++++++++ Package.swift | 33 ++++ README.md | 3 + Sources/CrudRouter/CrudRouter.swift | 74 ++++++++ Tests/CrudRouterTests/CrudRouterTests.swift | 15 ++ Tests/CrudRouterTests/XCTestManifests.swift | 9 + Tests/LinuxMain.swift | 7 + 8 files changed, 323 insertions(+) create mode 100644 .gitignore create mode 100644 Package.resolved create mode 100644 Package.swift create mode 100644 README.md create mode 100644 Sources/CrudRouter/CrudRouter.swift create mode 100644 Tests/CrudRouterTests/CrudRouterTests.swift create mode 100644 Tests/CrudRouterTests/XCTestManifests.swift create mode 100644 Tests/LinuxMain.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..02c0875 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..21c4ecd --- /dev/null +++ b/Package.resolved @@ -0,0 +1,178 @@ +{ + "object": { + "pins": [ + { + "package": "Console", + "repositoryURL": "https://github.com/vapor/console.git", + "state": { + "branch": null, + "revision": "5b9796d39f201b3dd06800437abd9d774a455e57", + "version": "3.0.2" + } + }, + { + "package": "Core", + "repositoryURL": "https://github.com/vapor/core.git", + "state": { + "branch": null, + "revision": "eb876a758733166a4fb20f3f0a17b480c5ea563e", + "version": "3.4.3" + } + }, + { + "package": "Crypto", + "repositoryURL": "https://github.com/vapor/crypto.git", + "state": { + "branch": null, + "revision": "5605334590affd4785a5839806b4504407e054ac", + "version": "3.3.0" + } + }, + { + "package": "DatabaseKit", + "repositoryURL": "https://github.com/vapor/database-kit.git", + "state": { + "branch": null, + "revision": "3a17dbbe9be5f8c37703e4b7982c1332ad6b00c4", + "version": "1.3.1" + } + }, + { + "package": "Fluent", + "repositoryURL": "https://github.com/vapor/fluent.git", + "state": { + "branch": null, + "revision": "270b6fa372f03809b9795e8f8b9d1c31267a0ff3", + "version": "3.0.0" + } + }, + { + "package": "HTTP", + "repositoryURL": "https://github.com/vapor/http.git", + "state": { + "branch": null, + "revision": "9e3eff9dfa4df7fc282bf27f801c72b3ffbfd984", + "version": "3.1.4" + } + }, + { + "package": "Multipart", + "repositoryURL": "https://github.com/vapor/multipart.git", + "state": { + "branch": null, + "revision": "e57007c23a52b68e44ebdfc70cbe882a7c4f1ec3", + "version": "3.0.2" + } + }, + { + "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": "SQL", + "repositoryURL": "https://github.com/vapor/sql.git", + "state": { + "branch": null, + "revision": "a35cf1dced4ddd32bb2dc8b6e765aea7bcf8d6e0", + "version": "2.1.0" + } + }, + { + "package": "swift-nio", + "repositoryURL": "https://github.com/apple/swift-nio.git", + "state": { + "branch": null, + "revision": "5d8148c8b45dfb449276557f22120694567dd1d2", + "version": "1.9.5" + } + }, + { + "package": "swift-nio-ssl", + "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", + "state": { + "branch": null, + "revision": "8380fa29a2af784b067d8ee01c956626ca29f172", + "version": "1.3.1" + } + }, + { + "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": "db35b1c35aabd0f5db3abca0cfda7becfe9c43e2", + "version": "1.1.0" + } + }, + { + "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": "156f8adeac3440e868da3757777884efbc6ec0cc", + "version": "2.1.0" + } + }, + { + "package": "Vapor", + "repositoryURL": "https://github.com/vapor/vapor.git", + "state": { + "branch": null, + "revision": "157d3b15336caa882662cc75024dd04b2e225246", + "version": "3.1.0" + } + }, + { + "package": "WebSocket", + "repositoryURL": "https://github.com/vapor/websocket.git", + "state": { + "branch": null, + "revision": "149af03348f60ac8b84defdf277112d62fd8c704", + "version": "1.0.2" + } + } + ] + }, + "version": 1 +} diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..160adea --- /dev/null +++ b/Package.swift @@ -0,0 +1,33 @@ +// swift-tools-version:4.2 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "CrudRouter", + products: [ + // Products define the executables and libraries produced by a package, and make them visible to other packages. + .library( + name: "CrudRouter", + targets: ["CrudRouter"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + // 💧 A server-side Swift web framework. + .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"), + + // 🔵 Swift ORM (queries, models, relations, etc) built on SQLite 3. + .package(url: "https://github.com/vapor/fluent.git", from: "3.0.0") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "CrudRouter", + dependencies: ["Fluent", "Vapor"]), + .testTarget( + name: "CrudRouterTests", + dependencies: ["CrudRouter"]), + ] +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..4bb15a9 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# CrudRouter + +A description of this package. diff --git a/Sources/CrudRouter/CrudRouter.swift b/Sources/CrudRouter/CrudRouter.swift new file mode 100644 index 0000000..f488ea8 --- /dev/null +++ b/Sources/CrudRouter/CrudRouter.swift @@ -0,0 +1,74 @@ +import Vapor +import Fluent + +public protocol CrudControllerProtocol { + associatedtype ModelType: Model, Content where ModelType.ID: Parameter + func indexAll(_ req: Request) throws -> Future<[ModelType]> + func index(_ req: Request) throws -> Future + func update(_ req: Request) throws -> Future + func create(_ req: Request) throws -> Future + func delete(_ req: Request) throws -> Future +} + +public extension CrudControllerProtocol { + func indexAll(_ req: Request) throws -> Future<[ModelType]> { + return ModelType.query(on: req).all().map { Array($0) } + } + + func index(_ req: Request) throws -> Future { + let id: ModelType.ID = try getId(from: req) + return ModelType.find(id, on: req).unwrap(or: Abort(.notFound)) + } + + func create(_ req: Request) throws -> Future { + return try req.content.decode(ModelType.self).flatMap { model in + return model.save(on: req) + } + } + + func update(_ req: Request) throws -> Future { + let id: ModelType.ID = try getId(from: req) + return try req.content.decode(ModelType.self).flatMap { model in + var temp = model + temp.fluentID = id + return temp.update(on: req) + } + } + + func delete(_ req: Request) throws -> Future { + let id: ModelType.ID = try getId(from: req) + return ModelType + .find(id, on: req) + .unwrap(or: Abort(.notFound)) + .flatMap { model in + return model.delete(on: req).transform(to: HTTPStatus.ok) + } + } +} + +fileprivate extension CrudControllerProtocol { + func getId(from req: Request) throws -> T { + guard let id = try req.parameters.next(ModelType.ID.self) as? T else { fatalError() } + + return id + } +} + +fileprivate final class CrudController: CrudControllerProtocol where T.ID: Parameter, T: Content { + typealias ModelType = T +} + +public extension Router { + func crudRegister( + _ path: PathComponentsRepresentable..., + for type: ModelType.Type + ) where ModelType.ID: Parameter { + let controller = CrudController() + + self.get(path, CrudController.ModelType.ID.parameter, use: controller.index) + self.get(path, use: controller.indexAll) + self.post(path, use: controller.create) + self.put(path, CrudController.ModelType.ID.parameter, use: controller.update) + self.delete(path, CrudController.ModelType.ID.parameter, use: controller.delete) + } +} diff --git a/Tests/CrudRouterTests/CrudRouterTests.swift b/Tests/CrudRouterTests/CrudRouterTests.swift new file mode 100644 index 0000000..1db4ca7 --- /dev/null +++ b/Tests/CrudRouterTests/CrudRouterTests.swift @@ -0,0 +1,15 @@ +import XCTest +@testable import CrudRouter + +final class CrudRouterTests: XCTestCase { + func testExample() { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(CrudRouter().text, "Hello, World!") + } + + static var allTests = [ + ("testExample", testExample), + ] +} diff --git a/Tests/CrudRouterTests/XCTestManifests.swift b/Tests/CrudRouterTests/XCTestManifests.swift new file mode 100644 index 0000000..eca492b --- /dev/null +++ b/Tests/CrudRouterTests/XCTestManifests.swift @@ -0,0 +1,9 @@ +import XCTest + +#if !os(macOS) +public func allTests() -> [XCTestCaseEntry] { + return [ + testCase(CrudRouterTests.allTests), + ] +} +#endif \ No newline at end of file diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 0000000..29573f4 --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,7 @@ +import XCTest + +import CrudRouterTests + +var tests = [XCTestCaseEntry]() +tests += CrudRouterTests.allTests() +XCTMain(tests) \ No newline at end of file