-
Notifications
You must be signed in to change notification settings - Fork 301
Description
I would like to be able to define a Haskell type that can be contained in multiple database fields.
This has two example use cases:
Inlining Records
Suppose I have a datatype like
data Tax = Tax { location :: Text, amount :: Integer }I want to include this on a record. I can manually use a schema like:
Purchase1
subtotal Integer
taxLocation Text
taxAmount Integerand then define an intermediary data model
data Purchase2 = Purchase2
{ purchaseSubtotal :: Integer
, purchaseTax :: Tax
}and relevant conversion functions.
However, I'd prefer to write something like:
Purchase3
subtotal Integer
tax (Inline Tax)which would "expand" to a schema like Purchase1 defined above. The Inline type can be used to distinguish inlining the columns vs a composite type (which Postgres supports, and possible other databases).
"One Of" sum types
Suppose I write a data type like
data Choice
= A Int
| B
| C Char
| D
And I want to include this model in a field. One option is to "inline" the constructors as nullable value fields, and then use a CHECK constraint to ensure that exactly one value is present.
So a schema like:
User
name Text
choice (OneOf Choice)could expand out to:
CREATE TABLE user (
id SERIAL PRIMARY KEY,
choice_a INT,
choice_b BOOL,
choice_c CHAR,
choice_d BOOL,
CHECK (
( choice_a IS NOT NULL AND choice_b IS NULL AND choice_c IS NULL AND choice_d IS NULL)
OR
( etc etc etc )
)Then parsing code can safely assume that exactly one is present and provide the right constructor. This is an automated way of doing "absorption" on sub-tables, where it would be error prone to do so in app code.
As far as I can tell, this would require modifying the PersistField and PersistFieldSql definitions to be able to talk about a variable amount of columns. I'm not sure the best way to approach that would be.