Comments (7)
It turns out String enums are a bit more gnarly. I start with a global RawRepresentable
extension which is identical to the Int version except for the where
clause:
extension RawRepresentable where RawValue == String {
static var postgreSQLDataType: PostgreSQLDataType {
return Self.postgreSQLDataType
}
static var postgreSQLDataArrayType: PostgreSQLDataType {
return Self.postgreSQLDataArrayType
}
static func convertFromPostgreSQLData(_ data: PostgreSQLData) throws -> Self {
let aRawValue = try RawValue.convertFromPostgreSQLData(data)
guard let enumValue = Self(rawValue: aRawValue) else {
throw Abort(.badRequest, reason: "Invalid enum value")
}
return enumValue
}
func convertToPostgreSQLData() throws -> PostgreSQLData {
return try self.rawValue.convertToPostgreSQLData()
}
}
Now I can define String enums like this:
enum Status : String, Codable {
case uninitialized, created, claimed, expired
}
extension Status : KeyStringDecodable, PostgreSQLDataCustomConvertible, PostgreSQLColumnStaticRepresentable {
static var postgreSQLColumn: PostgreSQLColumn = RawValue.postgreSQLColumn
static var keyStringTrue: Status = .created
static var keyStringFalse: Status = .uninitialized
}
Interestingly, I have to define postgreSQLColumn
in the enum extension. If I try to conform to it in a protocol extension, the compiler can't figure out which method to use, because some other protocol (maybe PostgreSQLDataCustomConvertible
?) already defines postgreSQLColumn
.
In any case, it feels pretty clunky. Especially the KeyStringDecodable
conformance, which forces me to specify a "truthiness" for the enum…
from fluent-postgres-driver.
Okay, a bit more detail. With the following extension, I can more easily conform Int
enums to PostgreSQLDataCustomConvertible
:
extension RawRepresentable where RawValue == Int {
static var postgreSQLDataType: PostgreSQLDataType {
return Self.postgreSQLDataType
}
static var postgreSQLDataArrayType: PostgreSQLDataType {
return Self.postgreSQLDataArrayType
}
static func convertFromPostgreSQLData(_ data: PostgreSQLData) throws -> Self {
let intData = try RawValue.convertFromPostgreSQLData(data)
guard let auth = Self(rawValue: intData) else {
throw Abort(.badRequest, reason: "Invalid enum value")
}
return auth
}
func convertToPostgreSQLData() throws -> PostgreSQLData {
return try self.rawValue.convertToPostgreSQLData()
}
}
Now I can do the following:
enum Status : Int, Codable {
case uninitialized, created, claimed, expired
}
extension Status : PostgreSQLDataCustomConvertible { }
…and the enum can be used within a Model
as expected. Personally, I think it's acceptable for the user to manually extend the enum to PostgreSQLDataCustomConvertible
by using the line:
extension Status : PostgreSQLDataCustomConvertible { }
This follows the pattern set by other extensions such as:
extension User: PostgreSQLModel
etc.
from fluent-postgres-driver.
@bensyverson, yeah that would be great! The PostgreSQLDataCustomConvertible
extension should go in vapor/postgresql
.
from fluent-postgres-driver.
I would try:
extension RawRepresentable where RawValue: PostgreSQLDataCustomConvertible {
...
}
Then at least it would be a simple matter of just adding:
extension MyEnum: PostgreSQLDataCustomConvertible { }
If that works, we can definitely add the generic RawRepresentable
extension to the vapor/postgresql package.
extension RawRepresentable where RawValue: PostgreSQLColumnStaticRepresentable {
...
}
This ^ as well, which we could add to the vapor/fluent-postgresql package to make column representation just another simple conformance.
Regarding the KeyStringDecodable
, unfortunately there's no way around that as Swift doesn't offer us any methods for discovering the available cases on an enum at runtime (cc @gwynne). There are certainly ways to hack this using knowledge of the ABI, but we'd really like to avoid that.
IIRC, there are some swift evolution proposals up for solutions to this enum case discovery problem.
With the above extensions added by vapor/fluent-postgres and vapor/postgresql, we could at least simplify things to look like:
enum Status : String, Codable {
case uninitialized, created, claimed, expired
}
extension Status: KeyStringDecodable, PostgreSQLType {
static var keyStringTrue: Status = .created
static var keyStringFalse: Status = .uninitialized
}
from fluent-postgres-driver.
@tanner0101 Oh, cool, that worked! Using the following extension:
extension RawRepresentable where RawValue: PostgreSQLDataCustomConvertible {
static var postgreSQLDataType: PostgreSQLDataType {
return Self.postgreSQLDataType
}
static var postgreSQLDataArrayType: PostgreSQLDataType {
return Self.postgreSQLDataArrayType
}
static func convertFromPostgreSQLData(_ data: PostgreSQLData) throws -> Self {
let aRawValue = try RawValue.convertFromPostgreSQLData(data)
guard let enumValue = Self(rawValue: aRawValue) else {
throw Abort(.badRequest, reason: "Invalid enum value")
}
return enumValue
}
func convertToPostgreSQLData() throws -> PostgreSQLData {
return try self.rawValue.convertToPostgreSQLData()
}
}
I can now do this:
enum Status : String, Codable {
case uninitialized, created, claimed, expired
}
extension Status : KeyStringDecodable, PostgreSQLDataCustomConvertible, PostgreSQLColumnStaticRepresentable {
static var postgreSQLColumn: PostgreSQLColumn = RawValue.postgreSQLColumn
static var keyStringTrue: Status = .created
static var keyStringFalse: Status = .uninitialized
}
Thanks! Should I wrap the extension up in a PR?
from fluent-postgres-driver.
Merged in vapor/postgresql, thanks!
from fluent-postgres-driver.
@tanner0101 What needs to happen in vapor/fluent-postgresql
inside the closure you mentioned? Is it just the following?
extension RawRepresentable where RawValue: PostgreSQLColumnStaticRepresentable {
static var postgreSQLColumn: PostgreSQLColumn = RawValue.postgreSQLColumn
}
If so, I can send a PR through on this repo so we can get that tighter syntax you outlined!
from fluent-postgres-driver.
Related Issues (20)
- updatedAt is incorrect after save HOT 2
- Accept URL string in configuration HOT 3
- Saving optional enum (nil) triggers: [ WARNING ] bind $3 type (UNKNOWN 0) does not match expected parameter type (TEXT) HOT 5
- 2.0.0 GM
- Type date but expression is of type text (transformAssignedExpr) HOT 5
- Migrations are now creating int8 fields as char in the DB and then the value gets messed up when querying HOT 1
- Aggregate SUM function fails HOT 1
- Sort by multiple field keys fail
- Postgres error thrown when using advised UUID ID field HOT 1
- [Feature request] Support JSONB column type for nested arrays / PostgreSQL
- simpleQuery flattens columns names to lower case HOT 1
- [Documentation] - We need thorough documentation on README or Wiki HOT 3
- Missing '#include <stdlib.h>'; 'abort' must be declared before it is used HOT 3
- debug logging no longer shows the RAW SQL HOT 4
- let user specify Postgres schema in the connection parameters. HOT 2
- Enum Migration: Adding multiple new cases to an already existing enum does only add the last case HOT 5
- No DEFERRABLE Constraint option
- DatabaseConfigurationFactory build error in 2.7.0 HOT 4
- Select SQL query for the fluent-postgres-driver with bindings
- PSQLError: Opening new connection for pool failed HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from fluent-postgres-driver.