GithubHelp home page GithubHelp logo

vapor / fluent-postgres-driver Goto Github PK

View Code? Open in Web Editor NEW
146.0 146.0 52.0 316 KB

🐘 PostgreSQL driver for Fluent.

License: MIT License

Swift 100.00%
fluent fluent-database fluent-driver postgresql server-side-swift swift swift-linux vapor vapor-service

fluent-postgres-driver's Introduction

Vapor

Documentation Team Chat MIT License Continuous Integration Code Coverage Swift 5.7+ Mastodon


Vapor is an HTTP web framework for Swift. It provides a beautifully expressive and easy-to-use foundation for your next website, API, or cloud project.

Take a look at some of the awesome stuff created with Vapor.

💧 Community

Join the welcoming community of fellow Vapor developers on Discord.

🚀 Contributing

To contribute a feature or idea to Vapor, create an issue explaining your idea or bring it up on Discord.

If you find a bug, please create an issue.

If you find a security vulnerability, please contact [email protected] as soon as possible.

💛 Sponsors

Support Vapor's development by becoming a sponsor.

Broken Hands Emerge Tools Jari Donut Dane MacStadium

💚 Backers

Support Vapor's development by becoming a backer.

Moritz LangMaarten EngelsThomas KrajacicJesse TiptonSteve HumeMikkel UlstrupGeoffrey FosterPaul SchmiedmayerScott RobbinsSven A. SchmidtSpencer CurtisZach RausnitzTim „Timinator“ KretzschmarKlaasAndrew Edwards+Li, Inc.Stijn WillemsKyle NewsomeVia Aurelia SolutionsJakub KiermaszBrian DrellingMattes MohrJamieGalen RhodesLitmapsDavid RomanBrian StrobachKishikawa KatsumiAlex SherbakovSidetrackGreg KarpatiFrantišek MikšJeremy GreenwoodRay FixMićo MiloložaAlanJonas SannewaldTapEnvy.us, LLCJawadPARAIPAN SORINKalyn DavisYR ChenAarón Martínez Cuevas

fluent-postgres-driver's People

Contributors

0xtim avatar bdrelling avatar bennydebock avatar calebkleveter avatar clayellis avatar gperdomor avatar gwynne avatar jaapwijnen avatar jccampagne avatar madsodgaard avatar mattpolzin avatar mihaelisaev avatar mrmage avatar noahpistilli avatar sandordobi avatar seeppp avatar siemensikkema avatar tanner0101 avatar twof avatar vkill avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fluent-postgres-driver's Issues

3.0 RC: PostgreSQL connection fails when supplying password and always fails in release builds

Connecting to PostgreSQL always fails in release builds, and it always fails in debug builds when you supply a password.

Steps to reproduce

1. Create user + database:

createuser bertandernie
createdb bigbird
psql
alter user bertandernie with encrypted password 'sesamestreet';
grant all privileges on database bigbird to bertandernie;
\q

2. Update configuration
Update configure.swift to have the following configuration:

    // Configure PostgreSQL Database
    let postgresConfig: PostgreSQLDatabaseConfig
    if env.name == "production" {
        // here you would probably have production credentials
        print("Using PostgreSQLDatabaseConfig as database user with supplying password")
        postgresConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "bertandernie", database: "bigbird", password: "sesamestreet")
    } else {
        // here you would have development credentials
        print("Using PostgreSQLDatabaseConfig as database user without supplying password")
        postgresConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "bertandernie", database: "bigbird")
    }
    let postgresDatabase = PostgreSQLDatabase(config: postgresConfig)
    databases.add(database: postgresDatabase, as: .psql)
    services.register(databases)

3. Build and run

$ swift build
Compile Swift Module 'App' (15 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/Run
 $ .build/x86_64-apple-macosx10.10/debug/Run
Running development build on macOS (non-release, debug mode)
Using PostgreSQLDatabaseConfig as database user without supplying password
Migrating psql DB
Migrations complete
Server starting on http://127.0.0.1:8080
^C $ .build/x86_64-apple-macosx10.10/debug/Run --env prod
Running production build on macOS (release, debug mode)
Using PostgreSQLDatabaseConfig as database user with supplying password
Migrating psql DB
Fatal error: Error raised at top level: ⚠️ PostgreSQL Error: No password is required
- id: PostgreSQLError.trust
: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-902.0.41/src/swift/stdlib/public/core/ErrorType.swift, line 191
Illegal instruction: 4
$ 

Observe that running the development build will connect properly when you don't supply a password, but it fails with PostgreSQL Error: No password is required when you do supply a password.

4. Build and run for release

$ swift build --configuration release
...
$ .build/x86_64-apple-macosx10.10/release/Run
Running development build on macOS (non-release, release mode)
Using PostgreSQLDatabaseConfig as database user without supplying password
Migrating psql DB
[PostgreSQL] dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "Cannot initialize PostgreSQLAuthenticationType from invalid Int32 value 8", underlyingError: nil))
^C $ .build/x86_64-apple-macosx10.10/release/Run --env prod
Running production build on macOS (release, release mode)
Using PostgreSQLDatabaseConfig as database user with supplying password
Migrating psql DB
[PostgreSQL] dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "Cannot initialize PostgreSQLAuthenticationType from invalid Int32 value 8", underlyingError: nil))
^C $ 

Observe that the release build will always fails with Cannot initialize PostgreSQLAuthenticationType from invalid Int32 value 8, regardless of whether or not you supply a password.

Adding unique on update fails

When modifying a table after creation, the migration fails, when adding index and unique to an existing field.

This code fails

static func prepare(on connection: PostgreSQLConnection) -> Future<Void> {
        return Database.update(User.self, on: connection) { builder in
            try builder.addIndex(to: \.username, isUnique: true)
        }
    }

With the following error
screen shot 2018-05-15 at 9 40 47 pm

Unable to save object with specified uuid ID

When I'm trying to save model to the database with specified UUID ID it saves with another random UUID ID. It looks like a bug.

In my case I'm trying to transfer data from another database and I really need to use my old UUIDs as PRIMARY KEY ID.

After some debugging I found where the problem is, we should check if UUID ID is already specified and only in case when it isn't fluent should generate random UUID.
Please take a look at this pull request #76
If everything is ok could someone please merge it and add it to the next release? 🙏

PostgreSQLModel should use Int64 (instead of int)

When utilizing PostgreSQLModel in Vapor 3 the int declared as the id is actually stored as a bigint in postgres according to pgadmin. However you cannot declare id as an Int64/bigint

final class myClass: Codable {
  var id: Int?
  var name: String
  var createdAt: Date?
  var updatedAt: Date?
  
  // MARK: Init
  init(name: String) {
    self.name = name
  }
  
  init(id: Int, name: String) {
    self.id = id
    self.name = name
  }
}

screen shot 2018-05-04 at 6 00 26 pm

if already being stored as a bigint in pg, I purpose just changing the int? to an Int64? to prevent breaking any bigint keys that already exist.

vapor + fluent-postgresql not Compile

hi. vapor is cool! nice work!
just started to take a vapor

  1. brew install vapor
  2. vapor new Hello --template=web
  3. cd Hello
  4. swift build -c releace >> fetching, Compile Swift Module, bla bla bla....
    Linking ./.build/x86_64-apple-macosx10.10/release/Run
  5. MacBook-Pro-sfclub:Hello sfclub$ ./.build/x86_64-apple-macosx10.10/release/Run
    The current hash key "0000000000000000" is not secure.
    Update hash.key in Config/crypto.json before using in production.
    Use openssl rand -base64 <length> to generate a random string.
    The current cipher key "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" is not secure.
    Update cipher.key in Config/crypto.json before using in production.
    Use openssl rand -base64 32 to generate a random string.
    No command supplied, defaulting to serve...
    Starting server on 0.0.0.0:8080
    All work fine!

After that I try to connect the module "Fluent PostgreSQL" as written in the documentation https://docs.vapor.codes/3.0/postgresql/fluent/

  1. Add lines to Package.swift:
    .package(url: "https://github.com/vapor/fluent-postgresql.git", from: "1.0.0-rc"),
    .target(name: "App", dependencies: ["FluentPostgreSQL", ...]),

  2. swift package update
    Fetching https://github.com/vapor/fluent-postgresql.git
    Updating https://github.com/vapor/leaf-provider.git
    Updating https://github.com/vapor/vapor.git
    Updating https://github.com/vapor/multipart.git
    Updating https://github.com/vapor/core.git
    Updating https://github.com/vapor/node.git
    Updating https://github.com/vapor/crypto.git
    Updating https://github.com/vapor/console.git
    Updating https://github.com/vapor/engine.git
    Updating https://github.com/vapor/bcrypt.git
    Updating https://github.com/vapor/json.git
    Updating https://github.com/vapor/routing.git
    Updating https://github.com/vapor/random.git
    Updating https://github.com/vapor/debugging.git
    Updating https://github.com/vapor/bits.git
    Updating https://github.com/vapor/ctls.git
    Updating https://github.com/vapor/tls.git
    Updating https://github.com/vapor/sockets.git
    Updating https://github.com/vapor/leaf.git
    Fetching https://github.com/vapor/fluent.git
    Fetching https://github.com/vapor/postgresql.git
    Fetching https://github.com/vapor/async.git <- hangs on this line indefinitely

in the system monitor, the swift-build process is 100% using cpu one core.
waited 2 days nothing changes.
tell me what I'm doing wrong?
found similar behavior but about mysql vapor/vapor#1413

No member 'logger'

My Package.resolved says I'm using this:

{
        "package": "FluentPostgreSQL",
        "repositoryURL": "https://github.com/vapor/fluent-postgresql.git",
        "state": {
          "branch": null,
          "revision": "e7011affaac21c60ce417139a376be8f21fd5815",
          "version": "1.0.0-rc.2.1.1"
        }
      },

When I try and compile I'm getting errors in PostgreSQLDatabase+LogSupporting.swift saying that there's no member 'logger', plus a bunch of other errors

screen shot 2018-04-25 at 10 41 38 pm

This is my Package.swift:

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "dts",
    dependencies: [
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0-rc.2"),
	.package(url: "https://github.com/vapor/fluent-postgresql.git", from: "1.0.0-rc"),
	.package(url: "https://github.com/vapor/leaf.git", from: "3.0.0-rc.2")
    ],
    targets: [
        .target(name: "App", dependencies: ["FluentPostgreSQL", "Vapor", "Leaf"]),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"])
    ]
)

I've done a clean, removed DerivedData directory, ran vapor update, and then regenerated and built the project.

add test for enum support

Add a test to ensure enums like the following are fully supported:

/// The Exact enum from my project
enum Availability: UInt8, Content {
    case everyday
    case sunday
    case monday
    case tuesday
    case wednesday
    case thursday
    case friday
    case saturday
}

[PostgreSQLError.fieldType: No PostgreSQL column type known for Dictionary<String, String>.]

With fluent-postgresql "1.0.0-rc.1.1", When there is a swift dictionary in the model, I get this error

[PostgreSQLError.fieldType: No PostgreSQL column type known for Dictionary<String, String>.] [Suggested fixes: Conform Dictionary<String, String> to `PostgreSQLColumnStaticRepresentable` to specify field type or implement a custom migration. Specify the `PostgreSQLColumn` manually using the schema builder in a migration.]

3.0-RC: Enums - No PostgreSQL column type known for <enum>

When I extend the User / Pet model to store PetType and UserType integer backed enums, PostgreSQL will fail on the UserType property on User:

screen shot 2018-02-28 at 10 37 10

Extended User / Pet model:

import Foundation
import FluentPostgreSQL
import Vapor

/// Pet

enum PetType: Int, Codable {
    case dog = 0
    case cat
    // It's pretty much my favorite animal. It's like a lion
    // and a tiger mixed... bred for its skills in magic.
    case liger
    case manBearPig
}

extension PetType: KeyStringDecodable {
    static var keyStringTrue: PetType {
        return .dog
    }
    
    static var keyStringFalse: PetType {
        return .cat
    }
}

struct Pet: PostgreSQLJSONType, Codable {
    var name: String
    var type: PetType
}

/// User

enum UserType: Int, Codable {
    case novice = 0
    case skilled
    case masterOfDisaster
}

extension UserType: KeyStringDecodable {
    static var keyStringTrue: UserType {
        return .novice
    }
    
    static var keyStringFalse: UserType {
        return .skilled
    }
}

final class User: PostgreSQLModel, Migration {
    static let idKey: WritableKeyPath<User, Int?> = \User.id
    var id: Int?
    var name: String
    var type: UserType = .novice
    var age: Int?
    var favoriteColors: [String]
    var pet: Pet
    
    init(id: Int? = nil, name: String, type: UserType, pet: Pet) {
        self.favoriteColors = []
        self.id = id
        self.name = name
        self.type = type
        self.pet = pet
    }
}

Changing the enum types from Integer backed to String backed does not matter:

enum UserType: String, Codable {
    case novice
    case skilled
    case masterOfDisaster
}

Note that PetType is not being used in the above code other than that it's part of the nested JSONB for Pet

query.sum() should be generic

Trying to get sum of money movements by calling

MoneyMovement.query(on: conn).sum(\MoneyMovement.quantity).flatMap { sumOfIncomes -> EventLoopFuture<Int64> in
    //somehow `sumOfIncomes` is Double, that's strange because `MoneyMovement.quantity` is Int64
}

but getting error

[ ERROR ] PostgreSQLError.binaryFloatingPoint: Could not decode Double from binary data type: NUMERIC.

2018-05-08 21 49 56

When saving empty object into DB its causing PostgreSQL to fail

[psql] [2018-07-27 13:21:53 +0000] INSERT INTO "chat_users" () VALUES () RETURNING * []
[ERR] ⚠️ [PostgreSQLError.server.error.scanner_yyerror: syntax error at or near ")"]
2018-07-27 09:21:53.865829-0400 Run[60108:4955773] ⚠️ [PostgreSQLError.server.error.scanner_yyerror: syntax error at or near ")"]

filter call no longer compiles

Now that FluentSQL went away this no longer compiles:

try ViewOrderPoint.query(on: req)
                            .filter(ViewOrderPoint.self, \ViewOrderPoint.orderID == order.id!)
                            .all()

It says the == is ambiguous.

Not working with Int64 array?

I have a model that looks like this:

struct Game: PostgreSQLModel, Codable {
var id: Int?
var tags: [Int64]?
}

I want to store an array of int64 tags in the model the case where there is multiple ints in the array works but also if the array is nil (empty) works.
But the case where it only contains a single value gives me:
DecodingError.typeMismatch: Value of type 'Int64' required for key ''.
But only on linux.
Using swift 4.1 + PostgreSQL 10 .

Database queries never complete

  • Vapor Toolbox: 3.1.4
  • OS: macOS
  • OS Version: 10.13.03
  • Vapor Framework: 3.0.0-beta.3.1.2

Expected Behavior

A request to the database completes

Current Behavior

A request to the database never completes

How to reproduce

1. create a new project

vapor new brokenPSQL --template=api --branch=beta

2. add FluentPostgreSQL as a dependencyin Package.swift

let package = Package(
    name: "psqlSaveIsHanging",
    dependencies: [
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0-beta"),
        .package(url: "https://github.com/vapor/fluent.git", from: "3.0.0-beta"),
        .package(url: "https://github.com/vapor/fluent-postgresql.git", from: "1.0.0-beta")
    ],
    targets: [
        .target(name: "App", dependencies: ["FluentSQLite", "FluentPostgreSQL", "Vapor"]),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"])
    ]
)

3. fetch dependencies + create xcode project

swift package generate-xcodeproj

4. open project and adjust Todo Model to conform to PostgreSQLModel

import FluentSQLite
import Vapor
import FluentPostgreSQL

/// A single entry of a Todo list.
final class Todo: PostgreSQLModel {
  ...
}

...

5. Set PostgreSQL as your database within configure.swift

import FluentPostgreSQL
import Foundation
import PostgreSQL
import Vapor

public func configure(
    _ config: inout Config,
    _ env: inout Environment,
    _ services: inout Services
) throws {
    // Register providers first
    try services.register(FluentPostgreSQLProvider())

    // Register routes to the router
    let router = EngineRouter.default()
    try routes(router)
    services.register(router, as: Router.self)

    // Configure a PostgrSQL database
    var databases = DatabaseConfig()
    let databaseConfig = PostgreSQLDatabaseConfig(
        hostname: "127.0.0.1",
        port: 5432,
        username: "yourUserName",
        database: "yourDatabaseName",
        password: nil
    )

    databases.add(database: PostgreSQLDatabase(config: databaseConfig), as: .psql)
    services.register(databases)

    // Configure migrations
    var migrations = MigrationConfig()
    migrations.add(model: Todo.self, database: .psql)
    services.register(migrations)
}

5. run the project and visit the site http://127.0.0.1:8080/todos

All you see is the site loads forever.

[Beta] Encode & Decode enums when possible

Summary

It might just be temporarily broken, but I haven't been able to get Int or String enums to encode & decode to PostgreSQL.

Details

It should be possible to do the following:

final class User: Codable, Content {
  enum Authorization : Int, Codable {
    case unauthorized = 0, member = 1, moderator = 2, admin = 3, owner = 4
  }
  var authorization: Authorization
}

However, this results in the following error:

[ ERROR ] PostgreSQL.PostgreSQLError.convertible: Unsupported encodable type: Authorization (PostgreSQLRowEncoder.swift:65)
[ DEBUG ] Suggested fixes for PostgreSQL.PostgreSQLError.convertible: Conform Authorization to PostgreSQLDataCustomConvertible (EngineServer.swift:198)

Despite the error, the table is being created properly:

miiine=# \d+ users;
                                                   Table "public.users"
    Column     |  Type   | Collation | Nullable |             Default              | Storage  | Stats target | Description 
---------------+---------+-----------+----------+----------------------------------+----------+--------------+-------------
 id            | bigint  |           | not null | generated by default as identity | plain    |              | 
 name          | text    |           | not null |                                  | extended |              | 
 username      | text    |           | not null |                                  | extended |              | 
 password      | text    |           | not null |                                  | extended |              | 
 authorization | integer |           | not null |                                  | plain    |              | 
Indexes:
    "users_pkey" PRIMARY KEY, btree (id)

Workarounds

I can manually serialize the value, but it's gross:

final class User: Codable, Content {
  enum Authorization : Int, Codable {
    case unauthorized = 0, member = 1, moderator = 2, admin = 3, owner = 4
  }
  var authorizationLevel : Int = Authorization.unauthorized.rawValue
  var authorization: Authorization {
    get {
      guard let auth = Authorization(rawValue: authorizationLevel) else {
        return .unauthorized
      }
      return auth
    }
    set (newValue) {
      self.authorizationLevel = newValue.rawValue
    }
  }
}

Similarly, I can manually conform to PostgreSQLDataCustomConvertible, but this is unwieldy and fragile:

enum Authorization : Int, Codable, PostgreSQLDataCustomConvertible {
  static var postgreSQLDataType: PostgreSQLDataType = RawValue.postgreSQLDataType
  
  static var postgreSQLDataArrayType: PostgreSQLDataType = RawValue.postgreSQLDataArrayType
  
  static func convertFromPostgreSQLData(_ data: PostgreSQLData) throws -> User.Authorization {
    let intData = try RawValue.convertFromPostgreSQLData(data)
    guard let auth = User.Authorization(rawValue: intData) else {
      throw Abort(.badRequest, reason: "Invalid auth level")
    }
    return auth
  }
  
  func convertToPostgreSQLData() throws -> PostgreSQLData {
    return try self.rawValue.convertToPostgreSQLData()
  }
  
  case unauthorized, member, moderator, admin, owner
}

Array encoding to JSONB

var participants: [Participant] = []

this property converted to single JSONB object while migration created as JSONB[] column

[ ERROR ] ⚠️ [PostgreSQLError.server.error.transformAssignedExpr: column "participants" is of type jsonb[] but expression is of type jsonb] [Suggested fixes: You will need to rewrite or cast the expression.] (RouterController.swift:976)

[Beta] Crash on Model save

Summary

In some circumstances, such as Auth middleware and unit tests, FluentPostgreSQL will crash with a nil DatabaseConnection as it's trying to build a query.

Detail

At Model<>.save(on:), FluentPostgreSQL crashes:

  • save(on:) tries return query(on: conn).save(self).transform(to: self)
  • query(on:) tries return .init(on: conn.connect(to: Self.defaultDatabase))
  • connect(to:) fails: codes.vapor.application (7): Assertion failed: Unexpected connect(to:): nil database identifier

This is despite the fact that the database identifier is explicitly passed in via the connection, and a default database is set on the model (in this case, User.defaultDatabase = .psql)

Steps to reproduce

  • Download the example project, run vapor xcode, open the Xcode project, then add User.swift to the AppTests target (how can I automate that?)
  • Test the project (Product > Test)

[Beta] Xcode crash on `PostgreSQLDatabaseConfig`

Summary

Calling PostgreSQLDatabaseConfig(hostname: port: username: database: password: ) on a database/user that doesn't require a password results in an Xcode crash, probably at the Swift compiler level.

Details

  • Using Xcode 9.2 (13772) and Vapor 3
  • And given a new database, initialized with:
$ createdb miiine
$ create user mine
$ psql miiine
miiine=# grant all privileges on database miiine to miiine;
miiine=# alter user miiine with encrypted password 'beyonceknowles';

…I can successfully connect using: let psqlDatabaseConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "miiine"). No password is required, given that psql -U miiine does connect.

…However, if I (incorrectly?) try to pass in the database name and user password:
let psqlDatabaseConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "miiine", database: "miiine", password: "beyonceknowles")

…I get a hard crash.

Results

First, Run crashes (Illegal instruction)

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes:       0x0000000000000001, 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Illegal instruction: 4
Termination Reason:    Namespace SIGNAL, Code 0x4
Terminating Process:   exc handler [0]

External Modification Warnings:
Debugger attached to process.

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libswiftCore.dylib            	0x000000010129faf0 specialized _assertionFailure(_:_:file:line:flags:) + 144
1   libswiftCore.dylib            	0x000000010114f8d2 swift_errorInMain + 322
2   Run                           	0x0000000100002390 main + 1120 (main.swift:6)
3   libdyld.dylib                 	0x00007fff6d373015 start + 1

Then Xcode comes down:

Crashed Thread:        27  <DBGLLDBSessionThread (pid=62812)>

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x00000000000000d8
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [0]
…
Thread 27 Crashed:: <DBGLLDBSessionThread (pid=62812)>
0   libsystem_pthread.dylib       	0x00007fff6d67d4a3 _pthread_mutex_lock_slow + 79
1   com.apple.CoreFoundation      	0x00007fff44e42013 CFRunLoopPerformBlock + 179
2   com.apple.dt.DVTFoundation    	0x0000000101afb78d _DVTAsyncPerformBlockOnMainRunLoop + 192
3   com.apple.dt.DVTFoundation    	0x0000000101afb6a0 DVTAsyncPerformBlock + 83
4   com.apple.dt.dbg.DebuggerLLDB 	0x000000010ec4fb5a -[DBGLLDBProcess _updateThreadStateAndStopReason:controlState:] + 1242

Steps to reproduce

  • Download the example project
  • Create a new database and set the name in Line 18 of /App/Setup/Configure.swift
  • Run Run to ensure that the password-less version is booting properly
  • Then change line 18:
    • from: let psqlDatabaseConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "miiine")
    • to: let psqlDatabaseConfig = PostgreSQLDatabaseConfig(hostname: "localhost", port: 5432, username: "miiine", database: "miiine", password: "beyonceknowles")
  • Now run Run again, and it should crash.

Error raised by constraint

When a column in the database has a unique index, and another row is attempted to be saved, the error that is returned is of type PostgreSQLDiagnosticResponse

currently, to be able to react upon this in a "nice" way in Vapor need to look at the error message to see if it contains something along the lines of "duplicate key"

It would be helpful if it would be possible to raise a specific error type based on a constraint failure, something like PostgreSQLConstraintError or something similar

Model `entity` not equal to `sqlTableIdentifierString`

struct Account: Content, Model, PostgreSQLTable {
    typealias Database = PostgreSQLDatabase
    typealias ID = Int
    static var idKey : WritableKeyPath<Account, Int?> = \Account.accountid
    static let entity = "account"
    
    var accountid:Int?
    var info:[accountinfo]
    var paid:Bool

}

extension Account{
    struct accountinfo : Content{
        var emailaddress:String
        var udid:String
        var udidtype:Int
        var pin:Int
    }
}
func boot(router: Router) throws {
        let accountRouter = router.grouped("account")
        accountRouter.get("quicky", use:quickTest)


func quickTest(_ req: Request) throws -> Future<[Account]> {
        return Account.query(on: req).filter(\Account.paid == true).all()
    }

request in browser:
http://localhost:8080/account/quicky

errorLog in the console:

Server starting on http://localhost:8080
[psql] [2018-07-01 02:11:14 +0000] SELECT * FROM "account" WHERE "Account"."paid" = $1 
[0x01 (BOOLEAN)] [ ERROR ] PostgreSQLError.server.error.errorMissingRTE: 
missing FROM-clause entry for table "Account" (Logger+LogError.swift:17)
[psql] [2018-07-01 02:13:01 +0000] SELECT * FROM "account" []

notice that the FROM is lower case "account" and the Where clause is uppercase 
"Account". dont know if this is the issue or not or provides some sort of hint as to 
what's going on. 

Notes: 
- that the database is already and existing database created manually not by any migration. 
- using Postgres v. 10.4 on localhost , Vapor 3.0.0+
- this works with just PostgreSQLModel but then i'm asked to conform by using an Int? 
which doesn't work for me in one of my tables that doesn't have a primary key so the 
concept of an 'id' isn't needed. 

Nested enums with same name overwrite each other

I'm seeing a behavior with PostgreSQLEnum that may need to be changed or documented as it is definitely something that isn't easily debugged.

If you have two nested enums with the same name, .e.g: Category.Kind and Transaction.Kind, the postgreSQLEnumTypeName for both will be the same (KIND). This means that when the migrations are run, the first will be overridden by the second. Inspecting the psql db and querying for types using \dT confirms this with a single listing for kind.

This is potentially misleading behavior as I should reasonably expect that since Category.Kind and Transaction.Kind are both unique enums in Swift, that the default migrations should provide two unique psql enums (perhaps category_kind and transaction_kind).

I haven't confirmed this behavior with other databases.

Current workarounds are:

  1. Provide a unique static postgreSQLEnumTypeName ("CATEGORY_KIND"), as well as a unique static migrationName ("Category.Kind"). Preferred, but it seems like this could be default behavior — each type, nested or not, should have their own unique migration name by default.
  2. Don't nest the enums and use a prefix (Category.Kind > CategoryKind). Not preferred because it's less Swifty.
  3. Choose unique names for each enum (Category.Kind, Transaction.Style). Not preferred because it's not very scalable across a large project, (the list of synonyms for "type/kind" is short.)

Adding filter using an empty array throws error

let operationalModes = try RestaurantOperationalHourMode.query(on: req).filter(\.id ~~ opertionHrModeIds).all()

opertionHrModeIds is an empty array

Thrown error log is shown below

[psql] [2018-05-18 04:34:25 +0000] select oid, relname from pg_class []
[psql] [2018-05-18 04:34:25 +0000] SELECT * FROM "tokens" WHERE ("tokens"."value" = $1) LIMIT 1 OFFSET 0 ["TEXT (binary) 7278D68E-1A48-495B-BD69-AA12489E20CB)"]
[psql] [2018-05-18 04:34:25 +0000] SELECT * FROM "users" WHERE ("users"."id" = $1) LIMIT 1 OFFSET 0 ["UUID (binary) »ïJé�$OG²\rvCñËÚY)"]
Getting restaurant
[psql] [2018-05-18 04:34:25 +0000] SELECT * FROM "restaurants" WHERE ("restaurants"."userId" = $1) ["UUID (binary) »ïJé�$OG²\rvCñËÚY)"]
[psql] [2018-05-18 04:34:25 +0000] SELECT * FROM "restaurantoperationalhourmodes" WHERE (0) []
[ ERROR ] PostgreSQLDiagnosticResponse.coerce_to_boolean: ERROR: argument of WHERE must be type boolean, not type integer (Logger+LogError.swift:17)
[ DEBUG ] Possible causes for PostgreSQLDiagnosticResponse.coerce_to_boolean: argument of WHERE must be type boolean, not type integer (Logger+LogError.swift:23)

Database name not correctly extracted from URL path.

Branch: nio

Swift Version: Swift 4.1 Snapshot 2018-03-16

When making a new Postgres database configuration using the database url in the format

postgres://user:password@host:port/databaseName

the database name extracted from the URL is prefixed with the "/" (which is expected behavior of of URL(string: "some url")?.path) and therefore the connection to the postgres database cannot be made successfully.

Tested same database config using PostgreSQLDatabaseConfig(hostname: port: username: , database: password: ) and connection to database worked fine so I know the database name is correct.

Sorry wrong repo. Moved to vapor/postgresql

declaring property of type PostgreSQLJSONType causes decode/encode failure

This is with a fresh build of Vapor using the beta branch. I can't seem to get my model to compile when using the jsonb type column in Postgres. Added at @tanner0101 request

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "test",
    dependencies: [
        // 💧 A server-side Swift web framework.
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0-rc"),

        // 🔵 Swift ORM (queries, models, relations, etc) built on SQLite 3.
        .package(url: "https://github.com/vapor/fluent-sqlite.git", from: "3.0.0-rc"),
        .package(url: "https://github.com/vapor/fluent-postgresql", from: "1.0.0-rc"),
    ],
    targets: [
        .target(name: "App", dependencies: ["FluentSQLite", "Vapor", "FluentPostgreSQL"]),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"]),
    ]
)
import Vapor
import Foundation
import FluentPostgreSQL

final class Test: Codable {
    var id: UUID?
    var fakeCol: PostgreSQLJSONType // comment me out and update init() for model to work
    
    init(fakeCol: PostgreSQLJSONType){
        self.fakeCol = fakeCol
    }
}
extension Test: PostgreSQLUUIDModel{}
extension Test: Content{}

withPooledConnection throws "nil database identifier"

Example:

return request.withPooledConnection(to: .psql, closure: { (db) -> Future<[User]> in
            return User.query(on: db).all()
    })

(or any other query on: db) throws "nil database identifier" in DatabaseConnection

Changing the Project to mysql works as expected.

unsupported jsonb version number 123

I have a one class and another one inside as a property. I don't want to create a new table for another simple class, make relationships etc for simple models. I tried that way:

final class Person: PostgreSQLUUIDModel {
  var id: UUID?
  var mails: [Mail]?
}

final class Mail: PostgreSQLJSONType {
  var name: String?
  var address: String?
}

But when I try to create object with that model I receive such error:

[ DEBUG ] Possible causes for PostgreSQLDiagnosticResponse.jsonb_recv: unsupported jsonb version number 123 (Logger+LogError.swift:23)

My PostgreSQL version is 10.3.

jsonb write fail

class TasksContainer: Codable, PostgreSQLJSONType  {
    var id: String
    var tasks: [String]
    init(id: String, tasks: [String]) {
        self.id = id
        self.tasks = tasks
    }
}
final class User: PostgreSQLStringModel {
...
var tasks: [TasksContainer]
...
}

On save I have this error "{"error":true,"reason":"ERROR: column "tasks" is of type jsonb but expression is of type jsonb[]"}"

json looks like below
"tasks":[{"id":"04242018","tasks":["one","two"]},{"id":"04242018","tasks":["three","four"]}]

If i change type to jsonb[] i have this error {"error":true,"reason":"ERROR: unsupported jsonb version number 123"}

Feature Request: Add support for case-insensitive collation (CITEXT) and/or lowercase indices

When e.g. searching for an email address in a user database, we'd want fast case-insensitive searches for email addresses and enforce uniqueness of lowercased email addresses.

For this, we could use the CITEXT type, but would need a way to specify it when creating a Fluent model. I recall a discussion about using a custom wrapper type this for custom SQL types, but can't find it. Essentially we could have a CaseInsensitiveString wrapping String to indicate that CITEXT should be used when creating the column. Is there an example of another type that does something similar (using a custom SQL type) already as a "sample" implementation?

Alternatively, we could create a lowercase index like CREATE UNIQUE INDEX unique_username_on_users ON users (lower(username));, but for that we'd need a way to specify lowercase conversions in fluent filters, for example (the .lower parts are the tricky ones, because they'd need to be passed to SQL):

try User
	.query(on: connection)
	.filter(\User.email.lower == emailAddress.lower)
	.first()

Also, I'm not sure how we'd best query that. Or should we just run custom SQL for that? If so, I assume we'd need to run this outside the schema creator in a separate statement?

Filtering by `PostgreSQLJSONType` field doesn't work

I have Test model with PostgreSQLJSONType field

import FluentPostgreSQL
import Vapor
import Foundation

final class Test: Content{
    
    struct SomeData: Codable, PostgreSQLJSONType, ReflectionDecodable {
        static func reflectDecoded() throws -> (SomeData, SomeData) {
            return (SomeData(hello: "one"), SomeData(hello: "two"))
        }
        
        static func reflectDecodedIsLeft(_ item: SomeData) throws -> Bool {
            let leftStr = String(data: try JSONEncoder().encode(try reflectDecoded().0), encoding: .utf8)
            let rightStr = String(data: try JSONEncoder().encode(item), encoding: .utf8)
            return leftStr == rightStr
        }
        var hello: String
    }
    
    var id: UUID?
    var data: SomeData
    
    init(data: SomeData) {
        self.data = data
    }
}

extension Test: Model {
    typealias Database = PostgreSQLDatabase
    
    typealias ID = UUID
    
    static var idKey: IDKey {
        return \.id
    }
}

extension Test: Parameter { }
extension Test: Migration {}

I added two new records into it

Test(data: Test.SomeData(hello: "world")).save(on: conn)
Test(data: Test.SomeData(hello: "vapor")).save(on: conn)

Then I'm trying to get records from Test model

import Vapor
import Fluent

public func boot(_ app: Application) throws {
    _ = app.requestPooledConnection(to: .psql).flatMap { conn -> EventLoopFuture<Void> in
        return Test.query(on: conn).all().map { tests -> Void in
            print("tests: \(tests)")
        }
    }.map { _ -> Void in
        print("tests done")
    }.catch { error in
        print("tests error: \(error)")
    }
}

and it works, it prints

tests: [App.Test, App.Test]
tests done

but when I'm trying to filter by JSON field

import Vapor
import Fluent

public func boot(_ app: Application) throws {
    _ = app.requestPooledConnection(to: .psql).flatMap { conn -> EventLoopFuture<Void> in
        return try Test.query(on: conn).filter(\Test.data.hello == "world").all().map { tests -> Void in
            print("tests: \(tests)")
        }
    }.map { _ -> Void in
        print("tests done")
    }.catch { error in
        print("tests error: \(error)")
    }
}

it throws an error

tests error: ⚠️ [PostgreSQLDiagnosticResponse.op_error: ERROR: operator does not exist: jsonb = text] [Possible causes: operator does not exist: jsonb = text] [Suggested fixes: No operator matches the given name and argument type(s). You might need to add explicit type casts.]

Optionals have not-null constraint in DB

I'm having a model that looks like this:

struct Customer: PostgreSQLModel {
    var id: Int?

    var name: String
    var pushId: String?
    var type: String
}
extension Customer: Migration {}

Now, when I'm trying to create a customer:

POST /api/customer HTTP/1.1
{
	"name": "Xav",
	"type": "iOS"
}

I'm getting an error: ERROR: null value in column \"pushId\" violates not-null constraint.

Looking in the psql database, I found that fluent generated the table with a not null constraint:

 Column |  Type  | Collation | Nullable |             Default              
--------+--------+-----------+----------+----------------------------------
 id     | bigint |           | not null | generated by default as identity
 name   | text   |           | not null | 
 pushId | text   |           | not null | 
 type   | text   |           | not null | 

Is this the intended behavior of Optionals with fluent-postgresql? If so, is there some documentation how to generate a nullable field?

Add support for URL

This is an enhancement request.

It would be nice to be able to use URL types in my model since URL is codable. They would obviously store as text in the database but would be mapped to a URL when coming from the database.

Upsert support

Can we add an UPSERT support? PostgreSQL has the ON CONFLICT clause for this purpose.

I could try to implement this.

PostgreSQL Binding fails

⚠️ [PostgreSQLDiagnosticResponse.exec_bind_message: ERROR: bind message supplies 2 parameters, but prepared statement "" requires 1] [Possible causes: bind message supplies 2 parameters, but prepared statement "" requires 1]

When executing

let stuff = Allergy.query(on: req).filter(\Allergy.id, in: allergyIds).all().map(to: [Allergy].self, { a in
    print(a)
    return a
}).catchMap({ (err) in
    print(err)
    return []
}).catch({ (err) in
    print(err)
})

This error is thrown to an encoding error it seems on something. I am using UUID's as id's for my tables. I have tested this in a clean project as well.

Update: It appears that the same thing happens when using an or group as well. I'm thinking that the UUID encoding is failing.

let items = Allergy.query(on: req).group(.or, closure: { builder in
    for id in allergyIds {
       builder.filter(\Allergy.id == id)
     }
}).count().do({ (amount) in
    print("Count: \(amount)")
}).catch({ (err) in
    print(err)
})

Can not convert a UInt8 enum back from Postgres

When trying to convert the data in Postgres back to a UInt8 enum fails with the error

[ ERROR ] DecodingError.typeMismatch: Value of type 'UInt8' required for key ''. (EngineServer.swift:157)

My enum extension is

extension RawRepresentable where RawValue == UInt8, Self: PostgreSQLColumnStaticRepresentable, Self: PostgreSQLDataConvertible {
    static var postgreSQLColumn: PostgreSQLColumn {
        return RawValue.postgreSQLColumn
    }
}

Saving data to the database works fine, just retrieving it fails.

Update: The same issue occurs when trying to decode an Int64 from the db

Model is not being saved when supplying ID, Does not save, Reports Success

func foo(objects: [Int:[Int]]) {
  for object in objects {
    let new_object = MyObjectModel(id: object.key, object.value)
    let result = createNewObject(db, new_object)
    
    result.whenSuccess( {object in
      print(object.id)
      print(object.indexList)
    })

    result.whenFailure ({error in
      print(error.localizedDescription)
    })
  }
}

func createNewObject(_ db: DatabaseConnectable, _ new_object: MyObjectModel) -> Future<MyObjectModel> {
  return new_object.save(on: db)
}

//MyObjectModel.swift
import Vapor
import Foundation
import FluentPostgreSQL

final class MyObjectModel: Codable {
  var id: OtherObject.ID? //Type = Int
  var indexList: [ADiffObject.ID] //Type = Int
  var createdAt: Date?
  var updatedAt: Date?
  
  init(id: OtherObject.ID, _ indexList: [ADiffObject.ID]) {
    self.id = id
    self.indexList = indexList
  }
}

// MARK: Required Extensions
extension MyObjectModel: PostgreSQLModel{}

extension MyObjectModel: Content {}
extension MyObjectModel: Migration {}
extension MyObjectModel: Parameter {}

extension MyObjectModel: Timestampable {
  static var createdAtKey: WritableKeyPath<MyObjectModel, Date?> {return \.createdAt}
  static var updatedAtKey: WritableKeyPath<MyObjectModel, Date?> {return \.updatedAt}
}


// MARK: Relationships
extension MyObjectModel {}

No Data is Saved to the Database, The Table is empty. I have dropped the table and let it get recreated. Result is the same. no data in table despite reporting success.

The when.Success Handler fires and prints:

    /// 275940
    /// [31, 43, 39, 75, 30, 319, 163, 1113, 28, 90, 34]
    /// 275938
    /// [31, 280, 39, 41, 28, 43, 75, 78, 30, 115, 42333]
    /// 275939
    /// [31, 280, 39, 28, 178, 43, 34, 29, 75, 42333]
    /// 279987
    /// [4077]
    /// 275946
    /// [336, 90, 31, 128, 43, 368]

Note: For Some Reason I could not get the "code block" to format correctly

Model is not being saved with a given ID. It is being saved with an ID assigned by Vapor instead.

The following is saved, but the ID that is saved to the database is not caa3ca53-c330-442d-a98b-53a1d918cd49. It is some other random ID provided by vapor.

extension DummyData: Migration {
    typealias Database = PostgreSQLDatabase
    static func prepare(on connection: PostgreSQLConnection) -> Future<Void> {
        let user = User(id:UUID("caa3ca53-c330-442d-a98b-53a1d918cd49"),
                     firstName: "test",
                     lastName: "user",
                     email: "[email protected]",
                     password: "password",
                     birthDate: "1994-01-02")
        return user.create(on: connection).transform(to: ())
    }
}

the class

final class User: Content {
    var id: UUID?
    let firstName: String
    let lastName: String
    var email: String
    var password: String
    let birthDate: String?
    var dateCreated: Date?
    var dateUpdated: Date?
    
    init(id: User.ID? = nil, firstName: String, lastName: String, email: String, password: String, birthDate: String?) {
        self.id        = id
        self.firstName = firstName
        self.lastName  = lastName
        self.email     = email
        self.birthDate = birthDate
        self.password  = password
    }
}
my resolved file ``` { "object": { "pins": [ { "package": "Auth", "repositoryURL": "https://github.com/vapor/auth.git", "state": { "branch": null, "revision": "b84242ee3d450516b050f7a64fc0b81604f56077", "version": "2.0.0-rc.4.1" } }, { "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": "a909eccc41941faac6fb9e511cdb9a5cb30a05de", "version": "3.1.7" } }, { "package": "Crypto", "repositoryURL": "https://github.com/vapor/crypto.git", "state": { "branch": null, "revision": "1b8c2ba5a42f1adf2aa812204678d8b16466fa59", "version": "3.1.2" } }, { "package": "DatabaseKit", "repositoryURL": "https://github.com/vapor/database-kit.git", "state": { "branch": null, "revision": "0db303439e5ef8b6df50a2b6c4029edddee90cb0", "version": "1.0.1" } }, { "package": "Fluent", "repositoryURL": "https://github.com/vapor/fluent.git", "state": { "branch": null, "revision": "8f22ef2dfeb278179a2d6e91769a5c1ceccf31ef", "version": "3.0.0-rc.2.4.1" } }, { "package": "FluentPostgreSQL", "repositoryURL": "https://github.com/vapor/fluent-postgresql.git", "state": { "branch": null, "revision": "8324bf0fc1437701f8963fb340c199c66079c90e", "version": "1.0.0-rc.2.3" } }, { "package": "HTTP", "repositoryURL": "https://github.com/vapor/http.git", "state": { "branch": null, "revision": "5e766f72d81ef5fe8805d704efdffd17e4906134", "version": "3.0.6" } }, { "package": "Multipart", "repositoryURL": "https://github.com/vapor/multipart.git", "state": { "branch": null, "revision": "7778dcb62f3efa845e8e2808937bb347575ba7ce", "version": "3.0.1" } }, { "package": "PostgreSQL", "repositoryURL": "https://github.com/vapor/postgresql.git", "state": { "branch": null, "revision": "4988607c3b2369248c6cfcd34274241a8632cd69", "version": "1.0.0-rc.2.2.1" } }, { "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": "1bb94271d8645b6d6983721080ad642aa35d749c", "version": "1.0.0" } }, { "package": "swift-nio", "repositoryURL": "https://github.com/apple/swift-nio.git", "state": { "branch": null, "revision": "a5db2a67515ad2b490ac5646db204a5edf939f47", "version": "1.6.1" } }, { "package": "swift-nio-ssl", "repositoryURL": "https://github.com/apple/swift-nio-ssl.git", "state": { "branch": null, "revision": "38955a5f806a952daf2b16fbfe9aa529749cf1dd", "version": "1.1.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": "43b57b5861d5181b906ac6411d28645e980bb638", "version": "1.0.1" } }, { "package": "URLEncodedForm", "repositoryURL": "https://github.com/vapor/url-encoded-form.git", "state": { "branch": null, "revision": "57cf7fb9c1a1014c50bc05123684a9139ad44127", "version": "1.0.3" } }, { "package": "Validation", "repositoryURL": "https://github.com/vapor/validation.git", "state": { "branch": null, "revision": "ab6c5a352d97c8687b91ed4963aef8e7cfe0795b", "version": "2.0.0" } }, { "package": "Vapor", "repositoryURL": "https://github.com/vapor/vapor.git", "state": { "branch": null, "revision": "8c73eebf7c41c7d8bf83ff87f550e0f97d6aadc4", "version": "3.0.2" } }, { "package": "WebSocket", "repositoryURL": "https://github.com/vapor/websocket.git", "state": { "branch": null, "revision": "141cb4d3814dc8062cb0b2f43e72801b5dfcf272", "version": "1.0.1" } } ] }, "version": 1 } ```

Conforming an `enum` to `ReflectionDecodable` makes Fluent create it as type `jsonb` instead of `int8`

(I am using all relevant packages on the master branch.)

I have an enum like this:

public enum EntityType: SwiftProtobuf.Enum {
  public typealias RawValue = Int
  case unknown // = 0
  case appActivity // = 1
  // more cases
  case UNRECOGNIZED(Int)

  public init() {
    self = .unknown
  }

  public init?(rawValue: Int) {
    switch rawValue {
    case 0: self = .unknown
    case 1: self = .appActivity
    // more cases
    default: self = .UNRECOGNIZED(rawValue)
    }
  }

  public var rawValue: Int {
    switch self {
    case .unknown: return 0
    case .appActivity: return 1
    // more cases
    case .UNRECOGNIZED(let i): return i
    }
  }

}

If I try to make this codable and encoded as an int8 as follows, using EntityType fields in a model creates table columns of type int8 as expected:


extension EntityType: Codable, PostgreSQLDataConvertible, ReflectionDecodable {
	public static var postgreSQLDataType: PostgreSQLDataType { return .int8 }
	public static var postgreSQLDataArrayType: PostgreSQLDataType { return .array(.int8) }
	
	public init(from decoder: Swift.Decoder) throws {
		let container = try decoder.singleValueContainer()
		self.init(rawValue: try container.decode(Int.self))!
	}
	
	public func encode(to encoder: Encoder) throws {
		var container = encoder.singleValueContainer()
		try container.encode(self.rawValue)
	}

	public static func convertFromPostgreSQLData(_ data: PostgreSQLData) throws -> EntityType {
		return EntityType(rawValue: try Int.convertFromPostgreSQLData(data))!
	}

	public func convertToPostgreSQLData() throws -> PostgreSQLData {
		return try self.rawValue.convertToPostgreSQLData()
	}
}

However, then I get runtime errors because the enum is not ReflectionDecodable. If I add ReflectionDecodable conformance like this:

extension EntityType: ReflectionDecodable {
	public static func reflectDecoded() throws -> (EntityType, EntityType) {
		return (.unknown, .appActivity)
	}
}

Then my migrations create the column as type jsonb instead and I get PostgreSQL errors like cannot compare jsonb = bigint for query filters like .filter(\MyModelType.entityType == .appActivity).

How can I ensure that Fluent creates my column of type .int8 even if conforming to ReflectionDecodable?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.