Search code examples
swiftxcodepostgresqlvaporvapor-fluent

Vapor 3 PostgreSQL CRUD without requests http


I am creating backend based on Vapor 3.1.10 using Xcode 11.2 and Swift 5.1, database is PostgreSQL 12. I have a question: how to interact with database (CRUD) without POST and GET requests. All tutorials show how to CRUD only based on Request through HTTPS. But what if my app needs to save something in database without interacting with network? Look at my code:

import Vapor
import FluentPostgreSQL

final class Device: PostgreSQLModel {        
    var id: Int?
    var isWorking: Bool
    var serial: Int

    init(isWorking: Bool, serial: Int) {
        self.isWorking = isWorking
        self.serial = serial
    }    
}
extension Device: Content {}
extension Device: Migration {}
extension Device: Parameter {}

classical method to write or read is:

import Vapor

final class DeviceController {        
    func readAll(_ req: Request) throws -> Future<[Device]> {
        return Device.query(on: req).all()
    }

    func create(_ req: Request) throws -> Future<Device> {
        return try req.content.decode(Device.self).flatMap { device in
            return device.save(on: req)
        }
    }
}

How to replace req to another background, safe thread, which I can create locally?

For example:

let device = Device(isWorking: true, serial: 54321)
device.save(on: <#T##DatabaseConnectable#>)

How to replace <#T##DatabaseConnectable#> ?

I will be thankful for any help or advice.


Solution

  • Based on this question and answers (Is is possible to use Vapor 3 Postgres Fluent in a standalone script?) I realized CRUD like this:

    import Vapor
    import FluentPostgreSQL
    
    final class Device: PostgreSQLModel {
        var id: Int?
        var isWorking: Bool
        var serial: Int
    
        init(isWorking: Bool, serial: Int) {
            self.isWorking = isWorking
            self.serial = serial
        }
    }
    extension Device: Content {}
    extension Device: Migration {}
    extension Device: Parameter {}
    
    final class WorkWithPostgres {
    
        let databaseConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "username", database: "testestest", password: nil)
    
        let database: PostgreSQLDatabase
    
        static let shared = WorkWithPostgres()
    
        private init() {
            database = PostgreSQLDatabase(config: databaseConfig)
        }
    
        func readAll<T: PostgreSQLModel>(postgreSQLModel: T.Type, completion: (([T]) -> Void)?) {
            let worker = MultiThreadedEventLoopGroup(numberOfThreads: 1)
            let conn = database.newConnection(on: worker)
    
            let _ = conn.map { connection in
                postgreSQLModel.query(on: connection).all().map { databaseData in
                    worker.shutdownGracefully { _ in
                    }
    
                    completion?(databaseData)
                }
            }
        }
    
        func create<T: PostgreSQLModel>(postgreSQLModel: T) {
            let worker = MultiThreadedEventLoopGroup(numberOfThreads: 1)
            let conn = database.newConnection(on: worker)
    
            let _ = conn.map { connection in
                let _ = postgreSQLModel.save(on: connection).whenComplete {
                    worker.shutdownGracefully { _ in
                    }
                }
            }
        }
    
    }
    
    final class DeviceController {
    
        func readAll(completion: (([Device]) -> Void)?) {
            WorkWithPostgres.shared.readAll(postgreSQLModel: Device.self) { devices in
                completion?(devices)
            }
        }
    
        func create(isWorking: Bool, serial: Int) {
            let device = Device(isWorking: isWorking, serial: serial)
    
            WorkWithPostgres.shared.create(postgreSQLModel: device)
        }
    
    }
    

    It is working, but I am not sure is it good way to do this. Does somebody know?