Skip to content

Feature request: PersistField types with multiple DB fieldsΒ #862

@parsonsmatt

Description

@parsonsmatt

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 Integer

and 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions