yesodweb / yesodweb/persistent

Feature request: PersistField types with multiple DB fields

Open
#862 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Haskell
Stars
486
Forks
306
PR merge metrics
No merged PRs in 30d

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the PersistField and PersistFieldSql definitions and the existing schema-generation path; the issue names no files or tests. Determine how variable-width fields, Inline records, and OneOf values would fit the supported database backends, then define acceptance cases for generated columns, constraints, and round-trip parsing before implementation.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
database
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.