-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Request: Allow for generating string enums for text
columns
#124
Comments
I think we should definitely do some more work here. It's low-hanging fruit with a lot of upside. These are the three variants I see of enums: postgres-level enumscreate type myenum as enum ('a', 'b', 'c'); These are already supported. If you want to change the set of values you can do that today with a schema snapshot rewrite (see below). fake enumsYou want This can almost be done with a schema snapshot rewrite. You can add a The only thing we need here is a hint to typo that it should not generate type assertions in the generated SQL. For instance when inserting a open enumsat $WORK we use the pattern where enums are represented as tables, and columns which uses the enums have a FK to the enum value table. This allows more flexible changes to the set of enum values, and postgres is aware of it. This currently doesn't have any special support in typo, but I have a branch I intend to finish soon. These will look something like this, which explicitly handles that you have known values and a possibility for unknown values to appear. /** Open enum
* - A
* - B
* - C
*/
sealed abstract class MyEnum(val value: String)
object MyEnum {
def apply(str: String): MyEnum =
ByName.getOrElse(str, Unknown(str))
case object A extends MyEnum("A")
case object B extends MyEnum("B")
case object C extends MyEnum("C")
case class Unknown(override val value: String) extends MyEnum(value)
val All: List[MyEnum] = List(A, B, C)
val ByName: Map[String, MyEnum] = All.map(x => (x.value, x)).toMap
} Database schema snapshot rewrite.Typo starts by fetching the entire database schema. Once we have that in memory, you're free to change it into anything you want before typo starts generating code. This is done through Options(
// ...
rewriteDatabase = metadb => {
val employed = db.RelationName(Some("myschema"), "employed")
metadb.copy(
enums = metadb.enums ++ List(
db.StringEnum(employed, List("YES", "NO"))
),
relations = metadb.relations.map {
case (name, lazyTable) =>
val rewrittenTable = lazyTable.map { case table: db.Table =>
name -> table.copy(
cols = table.cols.map {
case col if col.name.value == "is_employed" =>
col.copy(
tpe = db.Type.EnumRef(employed),
udtName = Some(employed.value),
)
case col => col
}
)
case notTable => notTable
}
(name, lazyTable)
}
)
}
) FutureSo the work to support fake enums is to add a So what's missing then is syntax and documentation. If you have any time to invest, any of (fake enums, sketching some more high-level syntax in |
That's a good taxonomy. Yes at $WORK we use "fake enums" for the flexibility outlined above. Open enums are also a great choice of course especially if the data changes or the DB is a point of coordination for the company, which in practice it often does become. I had the thought of altering the metadb to fake some enums as well but was concerned about the actual type in the jdbc layer, and about rewriting the tables to use it, which you've nicely demonstrated above. I did not realize that a For mapping to Very very rough sketch: trait TypeOverride {
--- def apply(relation: db.RelationName, colName: db.ColName): Option[String]
+++ def apply(relation: db.RelationName, colName: db.ColName): Option[OverrideType]
enum OverrideType = UserPickedClassName(String), FakeStringEnum(name: String, members: List[String], ...), FakeIntEnum(...) Might need a better name than 'fake' |
The
typo
generated string enums are really nice. They would eliminate our need to useenumeratum
, and of course have the very fast inlined-implicit doobie definitions.We make a lot of use of
text
columns in postgres which are enforced to be string enums at the application level. We find that adding (and removing) members in postgres enums is pretty difficult so enforcing at the application level but not in the DB schema is a sweet spot.I'd love to specify that a given column is a string enum (perhaps in something akin to type overrides) and have typo generate that enum and use that type for the column.
I think this could have other applications for columns where the application enforces a narrower set of values than the database schema itself, perhaps numeric enums as well where the type is
int
but the values are mapped as an enum in the system.The text was updated successfully, but these errors were encountered: