Safe Haskell | None |
---|
This module provides functions to generate the auxiliary structures for the user data type
- mkPersist :: CodegenConfig -> PersistDefinitions -> Q [Dec]
- groundhog :: QuasiQuoter
- groundhogFile :: QuasiQuoter
- data CodegenConfig = CodegenConfig {}
- defaultCodegenConfig :: CodegenConfig
- data NamingStyle = NamingStyle {
- mkDbEntityName :: String -> String
- mkEntityKeyName :: String -> String
- mkPhantomName :: String -> String -> Int -> String
- mkUniqueKeyPhantomName :: String -> String -> String -> String
- mkUniqueKeyConstrName :: String -> String -> String -> String
- mkUniqueKeyDbName :: String -> String -> String -> String
- mkDbConstrName :: String -> String -> Int -> String
- mkDbConstrAutoKeyName :: String -> String -> Int -> String
- mkDbFieldName :: String -> String -> Int -> String -> Int -> String
- mkExprFieldName :: String -> String -> Int -> String -> Int -> String
- mkExprSelectorName :: String -> String -> String -> Int -> String
- mkNormalFieldName :: String -> String -> Int -> Int -> String
- mkNormalDbFieldName :: String -> String -> Int -> Int -> String
- mkNormalExprFieldName :: String -> String -> Int -> Int -> String
- mkNormalExprSelectorName :: String -> String -> Int -> String
- suffixNamingStyle :: NamingStyle
- persistentNamingStyle :: NamingStyle
- conciseNamingStyle :: NamingStyle
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. The example below has all properties set explicitly.
data Settable = First {foo :: String, bar :: Int} deriving (Eq, Show) 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 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 fields: # List of constructor fields. If you don't change a field, you can omit it - name: foo dbName: foo # Column name exprName: FooField # Name of a field used in expressions - name: bar dbName: bar exprName: BarField uniques: - name: someconstraint fields: [foo, bar] # List of constructor parameter names. Not DB names(!) |]
which is equivalent to 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] |]
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
CodegenConfig | |
|
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
NamingStyle | |
|
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 ...