groundhog-th-0.4.0: Type-safe datatype-database mapping library.

Safe HaskellNone

Database.Groundhog.TH

Contents

Description

This module provides functions to generate the auxiliary structures for the user data type

Synopsis

Settings format

Groundhog needs to analyze the datatypes and create the auxiliary definitions before it can work with them. We use YAML-based settings to list the datatypes and adjust the result of their introspection.

A datatype can be treated as entity or embedded. An entity is stored in its own table, can be referenced in fields of other data, etc. It is a first-class value. An embedded type can only be a field of an entity or another embedded type. For example, the tuples are embedded. You can create your own embedded types and adjust the fields names of an existing embedded type individually for any place where it is used.

Unless the property is marked as mandatory, it can be omitted. In this case value created by the NamingStyle will be used.

data Settable = First {foo :: String, bar :: Int, next :: Maybe (Key Settable BackendSpecific)} deriving (Eq, Show)

-- The declaration with defaulted names

mkPersist defaultCodegenConfig [groundhog|
entity: Settable                       # If we did not want to add a constraint, this line would be enough
keys:
  - name: someconstraint
constructors:
  - name: First
    uniques:
      - name: someconstraint
        fields: [foo, bar]
 |]

Which is equivalent to the example below that has all properties set explicitly.

mkPersist defaultCodegenConfig [groundhog|
definitions:                           # First level key whose value is a list of definitions. It can be considered an optional header.
                                       # The list elements start with hyphen+space. Keys are separated from values by a colon+space. See full definition at http:yaml.orgspec1.2/spec.html.
  - entity: Settable                   # Mandatory. Entity datatype name
    dbName: Settable                   # Name of the main table
    # schema: public                   # Name of the schema to which the table belongs
    autoKey:                           # Description of the autoincremented key for data family Key instance
      constrName: SettableKey          # Name of constructor
      default: true                    # The default key is used when entity is referenced without key wrapper. E.g., "field :: SomeData" instead of "field :: Key SomeData keytype"
    keys:                              # List of the unique keys. An entity may have unique keys only if it has one constructor
      - name: someconstraint           # This name references names from uniques field of constructor
        keyPhantom: Someconstraint     # Name of phantom datatype that corresponds for each unique key
        constrName: SomeconstraintKey  # Name of data family Key instance constructor for this unique key
        dbName: Key#Someconstraint     # It is used for function "persistName" of "PersistField (Key Settable (Unique Someconstraint))"
        fields: []                     # Set fields that comprise this unique constraint. It works like setting fields in constructors
        mkEmbedded: false              # Defines if instance of "Embedded (Key Settable (Unique Someconstraint))" will be created. The "Selector" constructor names are defined by properties of key fields.
        default: false                 # Defines if this unique key is used as default
    constructors:                      # List of constructors. The constructors you don't change can be omitted
      - name: First                    # Mandatory. Constructor name
        phantomName: FooBarConstructor # Constructor phantom type name used to guarantee type safety
        dbName: First                  # Name of constructor table which is created only for datatypes with multiple constructors
        keyDbName: id                  # Name for the primary key column
        fields:                        # List of constructor fields. If you don't change a field, you can omit it
          - name: foo                  # The name as in constructor record. If constructor is not a record, the name is created by mkNormalFieldName. For example, the fields in constructor SomeConstr would have names someConstr0 and someConstr1 by default.
            dbName: foo                # Column name
            exprName: FooField         # Name of a field used in expressions
          # type: varchar              # This would result in having field type DbOther "varchar" instead of DbString. Value of this attribute will be used by DB backend for migration
          # default: foo_value         # The default value for column in the clause
          # reference:                 # This is explicit reference to a parent table not mapped by Groundhog
          #   schema: myschema         # Optional schema
          #   table: mytable           # Name of the parent table
          #   columns: [mytable_id]    # Parent columns. If the current field is embedded, e.g., a tuple, it will be a composite key
          #   onDelete: cascade        # Defines ON DELETE clause of references. It can have values: no action, restrict, cascade, set null, set default
          #   onUpdate: restrict       # Defines ON UPDATE
          # onDelete: cascade          # Clauses onDelete and onUpdate can be set outside of reference too. This is deprecated and kept for compatibility
          # If onDelete or onUpdate are omitted, the database will choose the action automatically. Note that it may differ across databases.
          # For example, MySQL has "restrict" by default, but in PostgreSQL it is "no action".
          - name: bar
            dbName: bar
            exprName: BarField
                                       # For some databases "type: integer" would be appropriate
          - name: next
            dbName: next
            exprName: NextField
        uniques:
          - name: someconstraint
            type: constraint           # The type can be be "constraint", "index", or "primary"
            fields: [foo, bar]         # List of constructor parameter names. Not DB names(!)
 |]

This is an example of embedded datatype usage.

data Company = Company {name :: String, headquarter :: Address, dataCentre :: Address, salesOffice :: Address} deriving (Eq, Show)
data Address = Address {city :: String, zipCode :: String, street :: String} deriving (Eq, Show)

mkPersist defaultCodegenConfig [groundhog|
definitions:
  - entity: Company
    constructors:
      - name: Company
        fields:
                                        # Property embeddedType of headquarter field is not mentioned, so the corresponding table columns will have names prefixed with headquarter (headquarter$city, headquarter$zip_code, headquarter$street)
          - name: dataCentre
            embeddedType:               # If a field has an embedded type you can access its subfields. If you do it, the database columns will match with the embedded dbNames (no prefixing).
              - name: city              # Just a regular list of fields. However, note that you should use default dbNames of embedded
                dbName: dc_city
              - name: zip_code          # Here we use embedded dbName (zip_code) which differs from the name used in Address definition (zipCode) for accessing the field.
                dbName: dc_zipcode
              - name: street
                dbName: dc_street
          - name: salesOffice
            embeddedType:               # Similar declaration, but using another syntax for YAML objects
              - {name: city, dbName: sales_city}
              - {name: zip_code, dbName: sales_zipcode}
              - {name: street, dbName: sales_street}
  - embedded: Address                        
    fields:                             # The syntax is the same as for constructor fields. Nested embedded types are allowed.
      - name: city                      # This line does nothing and can be omitted. Default settings for city are not changed.
      - name: zipCode
        dbName: zip_code                # Change column name.
                                        # Street is not mentioned so it will have default settings.
 |]

mkPersist :: CodegenConfig -> PersistDefinitions -> Q [Dec]Source

Creates the auxiliary structures. Particularly, it creates GADT Field data instance for referring to the fields in expressions and phantom types for data constructors. The default names of auxiliary datatypes and names used in database are generated using the naming style and can be changed via configuration. The datatypes and their generation options are defined via YAML configuration parsed by quasiquoter groundhog.

groundhog :: QuasiQuoterSource

Converts quasiquoted settings into the datatype used by mkPersist.

groundhogFile :: QuasiQuoterSource

Parses configuration stored in the file

 mkPersist suffixNamingStyle [groundhogFile|../groundhog.yaml|]

Settings for code generation

data CodegenConfig Source

Constructors

CodegenConfig 

Fields

namingStyle :: NamingStyle

Naming style that is applied for all definitions

migrationFunction :: Maybe String

Codegenerator will create a function with this name that will run migrate for each non-polymorphic entity in definition

When describing a datatype you can omit the most of the declarations. In this case the omitted parts of description will be automatically generated using the default names created by naming style. Any default name can be overridden by setting its value explicitly.

data NamingStyle Source

Defines how the names are created. The mk* functions correspond to the set* functions. Functions mkNormal* define names of non-record constructor Field

Constructors

NamingStyle 

Fields

mkDbEntityName :: String -> String

Create name of the table for the datatype. Parameters: data name.

mkEntityKeyName :: String -> String

Create name of the backend-specific key constructor for the datatype. Parameters: data name.

mkPhantomName :: String -> String -> Int -> String

Create name for phantom constructor used to parametrise Field. Parameters: data name, constructor name, constructor position.

mkUniqueKeyPhantomName :: String -> String -> String -> String

Create name for phantom unique key used to parametrise Key. Parameters: data name, constructor name, unique constraint name.

mkUniqueKeyConstrName :: String -> String -> String -> String

Create name of constructor for the unique key. Parameters: data name, constructor name, unique constraint name.

mkUniqueKeyDbName :: String -> String -> String -> String

Create name used by persistName for the unique key. Parameters: data name, constructor name, unique constraint name.

mkDbConstrName :: String -> String -> Int -> String

Create name of the constructor specific table. Parameters: data name, constructor name, constructor position.

mkDbConstrAutoKeyName :: String -> String -> Int -> String

Create name of the db field for autokey. Parameters: data name, constructor name, constructor position.

mkDbFieldName :: String -> String -> Int -> String -> Int -> String

Create name of the field column in a database. Parameters: data name, constructor name, constructor position, field record name, field position.

mkExprFieldName :: String -> String -> Int -> String -> Int -> String

Create name of field constructor used in expressions. Parameters: data name, constructor name, constructor position, field record name, field position.

mkExprSelectorName :: String -> String -> String -> Int -> String

Create name of selector (see Embedded) constructor used in expressions. Parameters: data name, constructor name, field record name, field position.

mkNormalFieldName :: String -> String -> Int -> Int -> String

Create field name used to refer to the it in settings for non-record constructors. Parameters: data name, constructor name, constructor position, field position.

mkNormalDbFieldName :: String -> String -> Int -> Int -> String

Create name of the field column in a database. Parameters: data name, constructor name, constructor position, field position.

mkNormalExprFieldName :: String -> String -> Int -> Int -> String

Create name of field constructor used in expressions. Parameters: data name, constructor name, constructor position, field position.

mkNormalExprSelectorName :: String -> String -> Int -> String

Create name of selector (see Embedded) constructor used in expressions. Parameters: data name, constructor name, field position.

suffixNamingStyle :: NamingStyleSource

Default style. Adds "Field" to each record field name.

Example:

 data SomeData a = Normal Int | Record { bar :: Maybe String, asc :: a}
 -- Generated code
 data NormalConstructor
 data RecordConstructor
 instance PersistEntity where
   data Field (SomeData a) where
     Normal0Field :: Field NormalConstructor Int
     BarField :: Field RecordConstructor (Maybe String)
     AscField :: Field RecordConstructor a
 ...

persistentNamingStyle :: NamingStyleSource

Creates field names in Persistent fashion prepending constructor names to the fields.

Example:

 data SomeData a = Normal Int | Record { bar :: Maybe String, asc :: a}
 -- Generated code
 data NormalConstructor
 data RecordConstructor
 instance PersistEntity where
   data Field (SomeData a) where
     Normal0 :: Field NormalConstructor Int
     RecordBar :: Field RecordConstructor (Maybe String)
     RecordAsc :: Field RecordConstructor a
 ...

conciseNamingStyle :: NamingStyleSource

Creates the shortest field names. It is more likely to lead in name conflicts than other naming styles.

Example:

 data SomeData a = Normal Int | Record { bar :: Maybe String, asc :: a}
 -- Generated code
 data NormalConstructor
 data RecordConstructor
 instance PersistEntity where
   data Field (SomeData a) where
     Normal0 :: Field NormalConstructor Int
     Bar :: Field RecordConstructor (Maybe String)
     Asc :: Field RecordConstructor a
 ...

lowerCaseSuffixNamingStyle :: NamingStyleSource

The generated Haskell names of phantom types (constructors, fields, etc.) are the same as with suffixNamingStyle. But the table names and columns are converted from camelCase to underscore_lower_case with toUnderscore.

toUnderscore :: String -> StringSource

Transforms string from camelCase to lower_case_underscore naming convention. ColumnName -> column_name, parseURL -> parse_url, FieldIEEE754Floating -> field_ieee754_floating