packages feed

groundhog-th 0.1.0.3 → 0.2.0

raw patch · 4 files changed

+235/−182 lines, 4 filesdep ~groundhogdep ~yamlPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: groundhog, yaml

API changes (from Hackage documentation)

- Database.Groundhog.TH.Settings: dataName :: THEntityDef -> Name
- Database.Groundhog.TH.Settings: dbConstrName :: THConstructorDef -> String
- Database.Groundhog.TH.Settings: dbEmbeddedName :: THEmbeddedDef -> String
- Database.Groundhog.TH.Settings: dbEntityName :: THEntityDef -> String
- Database.Groundhog.TH.Settings: dbFieldName :: THFieldDef -> String
- Database.Groundhog.TH.Settings: embeddedConstructorName :: THEmbeddedDef -> Name
- Database.Groundhog.TH.Settings: embeddedDef :: THFieldDef -> Maybe [PSEmbeddedFieldDef]
- Database.Groundhog.TH.Settings: embeddedFields :: THEmbeddedDef -> [THFieldDef]
- Database.Groundhog.TH.Settings: embeddedName :: THEmbeddedDef -> Name
- Database.Groundhog.TH.Settings: exprName :: THFieldDef -> String
- Database.Groundhog.TH.Settings: fieldName :: THFieldDef -> String
- Database.Groundhog.TH.Settings: fieldType :: THFieldDef -> Type
+ Database.Groundhog.TH.Settings: THUniqueDef :: String -> UniqueType -> [String] -> THUniqueDef
+ Database.Groundhog.TH.Settings: data THUniqueDef
+ Database.Groundhog.TH.Settings: instance FromJSON UniqueType
+ Database.Groundhog.TH.Settings: instance Lift UniqueType
+ Database.Groundhog.TH.Settings: instance Show THUniqueDef
+ Database.Groundhog.TH.Settings: psDbEmbeddedTypeName :: PSEmbeddedFieldDef -> Maybe String
+ Database.Groundhog.TH.Settings: psDbTypeName :: PSFieldDef -> Maybe String
+ Database.Groundhog.TH.Settings: psUniqueType :: PSUniqueDef -> Maybe UniqueType
+ Database.Groundhog.TH.Settings: thDataName :: THEntityDef -> Name
+ Database.Groundhog.TH.Settings: thDbConstrName :: THConstructorDef -> String
+ Database.Groundhog.TH.Settings: thDbEmbeddedName :: THEmbeddedDef -> String
+ Database.Groundhog.TH.Settings: thDbEntityName :: THEntityDef -> String
+ Database.Groundhog.TH.Settings: thDbFieldName :: THFieldDef -> String
+ Database.Groundhog.TH.Settings: thDbTypeName :: THFieldDef -> Maybe String
+ Database.Groundhog.TH.Settings: thEmbeddedConstructorName :: THEmbeddedDef -> Name
+ Database.Groundhog.TH.Settings: thEmbeddedDef :: THFieldDef -> Maybe [PSEmbeddedFieldDef]
+ Database.Groundhog.TH.Settings: thEmbeddedFields :: THEmbeddedDef -> [THFieldDef]
+ Database.Groundhog.TH.Settings: thEmbeddedName :: THEmbeddedDef -> Name
+ Database.Groundhog.TH.Settings: thExprName :: THFieldDef -> String
+ Database.Groundhog.TH.Settings: thFieldName :: THFieldDef -> String
+ Database.Groundhog.TH.Settings: thFieldType :: THFieldDef -> Type
+ Database.Groundhog.TH.Settings: thUniqueFields :: THUniqueDef -> [String]
+ Database.Groundhog.TH.Settings: thUniqueName :: THUniqueDef -> String
+ Database.Groundhog.TH.Settings: thUniqueType :: THUniqueDef -> UniqueType
- Database.Groundhog.TH.Settings: PSEmbeddedFieldDef :: String -> Maybe String -> Maybe [PSEmbeddedFieldDef] -> PSEmbeddedFieldDef
+ Database.Groundhog.TH.Settings: PSEmbeddedFieldDef :: String -> Maybe String -> Maybe String -> Maybe [PSEmbeddedFieldDef] -> PSEmbeddedFieldDef
- Database.Groundhog.TH.Settings: PSFieldDef :: String -> Maybe String -> Maybe String -> Maybe [PSEmbeddedFieldDef] -> PSFieldDef
+ Database.Groundhog.TH.Settings: PSFieldDef :: String -> Maybe String -> Maybe String -> Maybe String -> Maybe [PSEmbeddedFieldDef] -> PSFieldDef
- Database.Groundhog.TH.Settings: PSUniqueDef :: String -> [String] -> PSUniqueDef
+ Database.Groundhog.TH.Settings: PSUniqueDef :: String -> Maybe UniqueType -> [String] -> PSUniqueDef
- Database.Groundhog.TH.Settings: THConstructorDef :: Name -> String -> String -> Maybe String -> [THFieldDef] -> [PSUniqueDef] -> THConstructorDef
+ Database.Groundhog.TH.Settings: THConstructorDef :: Name -> String -> String -> Maybe String -> [THFieldDef] -> [THUniqueDef] -> THConstructorDef
- Database.Groundhog.TH.Settings: THFieldDef :: String -> String -> String -> Type -> Maybe [PSEmbeddedFieldDef] -> THFieldDef
+ Database.Groundhog.TH.Settings: THFieldDef :: String -> String -> Maybe String -> String -> Type -> Maybe [PSEmbeddedFieldDef] -> THFieldDef
- Database.Groundhog.TH.Settings: thConstrUniques :: THConstructorDef -> [PSUniqueDef]
+ Database.Groundhog.TH.Settings: thConstrUniques :: THConstructorDef -> [THUniqueDef]

Files

Database/Groundhog/TH.hs view
@@ -18,7 +18,7 @@   , conciseNamingStyle   ) where -import Database.Groundhog.Core (delim)+import Database.Groundhog.Core (delim, UniqueType(..)) import Database.Groundhog.Generic import Database.Groundhog.TH.CodeGen import Database.Groundhog.TH.Settings@@ -30,8 +30,9 @@ import Data.Char (toUpper, toLower, isSpace) import Data.Either (lefts) import Data.List (nub, (\\))-import Data.Maybe (fromMaybe, isNothing)-import Data.Yaml (decodeEither)+import Data.Maybe (fromMaybe, isJust, isNothing)+import Data.Yaml as Y(decodeHelper, ParseException(..))+import qualified Text.Libyaml as Y  data CodegenConfig = CodegenConfig {     -- | Naming style that is applied for all definitions@@ -184,19 +185,19 @@   return $ migrateFunc ++ concat decs  applyEntitySettings :: NamingStyle -> PSEntityDef -> THEntityDef -> THEntityDef-applyEntitySettings style settings def@(THEntityDef{..}) =-  def { dbEntityName = fromMaybe dbEntityName $ psDbEntityName settings+applyEntitySettings style PSEntityDef{..} def@(THEntityDef{..}) =+  def { thDbEntityName = fromMaybe thDbEntityName psDbEntityName       , thAutoKey = thAutoKey'-      , thUniqueKeys = maybe thUniqueKeys (map mkUniqueKey') $ psUniqueKeys settings+      , thUniqueKeys = maybe thUniqueKeys (map mkUniqueKey') psUniqueKeys       , thConstructors = thConstructors'       } where-  thAutoKey' = maybe thAutoKey (liftM2 applyAutoKeySettings thAutoKey) $ psAutoKey settings+  thAutoKey' = maybe thAutoKey (liftM2 applyAutoKeySettings thAutoKey) psAutoKey -  thConstructors' = maybe thConstructors'' (f thConstructors'') $ psConstructors settings where+  thConstructors' = maybe thConstructors'' (f thConstructors'') $ psConstructors where     thConstructors'' = maybe id (\_ -> zipWith putAutoKey [0..]) thAutoKey' thConstructors-    putAutoKey cNum cDef@(THConstructorDef{..}) = cDef {thDbAutoKeyName = Just $ mkDbConstrAutoKeyName style (nameBase dataName) (nameBase thConstrName) cNum}+    putAutoKey cNum cDef@(THConstructorDef{..}) = cDef {thDbAutoKeyName = Just $ mkDbConstrAutoKeyName style (nameBase thDataName) (nameBase thConstrName) cNum} -  mkUniqueKey' = mkUniqueKey style (nameBase dataName) (head thConstructors')+  mkUniqueKey' = mkUniqueKey style (nameBase thDataName) (head thConstructors')   f = foldr $ replaceOne "constructor" psConstrName (nameBase . thConstrName) applyConstructorSettings  mkUniqueKey :: NamingStyle -> String -> THConstructorDef -> PSUniqueKeyDef -> THUniqueKeyDef@@ -210,44 +211,46 @@   , thUniqueKeyMakeEmbedded = fromMaybe False psUniqueKeyMakeEmbedded   , thUniqueKeyIsDef = fromMaybe False psUniqueKeyIsDef   }-  f = foldr $ replaceOne "unique field" psFieldName fieldName applyFieldSettings+  f = foldr $ replaceOne "unique field" psFieldName thFieldName applyFieldSettings   uniqueFields = mkFieldsForUniqueKey style dName key cDef  applyAutoKeySettings :: THAutoKeyDef -> PSAutoKeyDef -> THAutoKeyDef-applyAutoKeySettings def@(THAutoKeyDef{..}) settings = -  def { thAutoKeyConstrName = fromMaybe thAutoKeyConstrName $ psAutoKeyConstrName settings-      , thAutoKeyIsDef = fromMaybe thAutoKeyIsDef $ psAutoKeyIsDef settings+applyAutoKeySettings def@(THAutoKeyDef{..}) PSAutoKeyDef{..} = +  def { thAutoKeyConstrName = fromMaybe thAutoKeyConstrName psAutoKeyConstrName+      , thAutoKeyIsDef = fromMaybe thAutoKeyIsDef psAutoKeyIsDef       }  applyConstructorSettings :: PSConstructorDef -> THConstructorDef -> THConstructorDef-applyConstructorSettings settings def@(THConstructorDef{..}) =-  def { thPhantomConstrName = fromMaybe thPhantomConstrName $ psPhantomConstrName settings-      , dbConstrName = fromMaybe dbConstrName $ psDbConstrName settings-      , thDbAutoKeyName = fromMaybe thDbAutoKeyName $ psDbAutoKeyName settings-      , thConstrFields = maybe thConstrFields (f thConstrFields) $ psConstrFields settings-      , thConstrUniques = fromMaybe thConstrUniques $ psConstrUniques settings+applyConstructorSettings PSConstructorDef{..} def@(THConstructorDef{..}) =+  def { thPhantomConstrName = fromMaybe thPhantomConstrName psPhantomConstrName+      , thDbConstrName = fromMaybe thDbConstrName psDbConstrName+      , thDbAutoKeyName = fromMaybe thDbAutoKeyName psDbAutoKeyName+      , thConstrFields = maybe thConstrFields (f thConstrFields) psConstrFields+      , thConstrUniques = maybe thConstrUniques (map convertUnique) psConstrUniques       } where-  f = foldr $ replaceOne "field" psFieldName fieldName applyFieldSettings+  f = foldr $ replaceOne "field" psFieldName thFieldName applyFieldSettings+  convertUnique (PSUniqueDef uName uType uFields) = THUniqueDef uName (fromMaybe UniqueConstraint uType) uFields    applyFieldSettings :: PSFieldDef -> THFieldDef -> THFieldDef-applyFieldSettings settings def@(THFieldDef{..}) =-  def { dbFieldName = fromMaybe dbFieldName $ psDbFieldName settings-      , exprName = fromMaybe exprName $ psExprName settings-      , embeddedDef = psEmbeddedDef settings+applyFieldSettings PSFieldDef{..} def@(THFieldDef{..}) =+  def { thDbFieldName = fromMaybe thDbFieldName psDbFieldName+      , thExprName = fromMaybe thExprName psExprName+      , thDbTypeName = psDbTypeName+      , thEmbeddedDef = psEmbeddedDef       }  applyEmbeddedSettings :: PSEmbeddedDef -> THEmbeddedDef -> THEmbeddedDef-applyEmbeddedSettings settings def@(THEmbeddedDef{..}) =-  def { dbEmbeddedName = fromMaybe dbEmbeddedName $ psDbEmbeddedName settings-      , embeddedFields = maybe embeddedFields (f embeddedFields) $ psEmbeddedFields settings+applyEmbeddedSettings PSEmbeddedDef{..} def@(THEmbeddedDef{..}) =+  def { thDbEmbeddedName = fromMaybe thDbEmbeddedName psDbEmbeddedName+      , thEmbeddedFields = maybe thEmbeddedFields (f thEmbeddedFields) psEmbeddedFields       } where-  f = foldr $ replaceOne "field" psFieldName fieldName applyFieldSettings+  f = foldr $ replaceOne "field" psFieldName thFieldName applyFieldSettings  mkFieldsForUniqueKey :: NamingStyle -> String -> THUniqueKeyDef -> THConstructorDef -> [THFieldDef]-mkFieldsForUniqueKey style dName uniqueKey cDef = zipWith (setSelector . findField) (psUniqueFields uniqueDef) [0..] where-  findField name = findOne "field" id fieldName name $ thConstrFields cDef-  uniqueDef = findOne "unique" id psUniqueName (thUniqueKeyName uniqueKey) $ thConstrUniques cDef-  setSelector f i = f {exprName = mkExprSelectorName style dName (thUniqueKeyConstrName uniqueKey) (fieldName f) i}+mkFieldsForUniqueKey style dName uniqueKey cDef = zipWith (setSelector . findField) (thUniqueFields uniqueDef) [0..] where+  findField name = findOne "field" id thFieldName name $ thConstrFields cDef+  uniqueDef = findOne "unique" id thUniqueName (thUniqueKeyName uniqueKey) $ thConstrUniques cDef+  setSelector f i = f {thExprName = mkExprSelectorName style dName (thUniqueKeyConstrName uniqueKey) (thFieldName f) i}  notUniqueBy :: Eq b => (a -> b) -> [a] -> [b] notUniqueBy f xs = let xs' = map f xs in nub $ xs' \\ nub xs'@@ -265,41 +268,47 @@ validateEntity def = do   let constrs = thConstructors def   assertUnique thPhantomConstrName constrs "constructor phantom name"-  assertUnique dbConstrName constrs "constructor db name"+  assertUnique thDbConstrName constrs "constructor db name"   forM_ constrs $ \cdef -> do     let fields = thConstrFields cdef     assertSpaceFree (thPhantomConstrName cdef) "constructor phantom name"-    assertUnique exprName fields "expr field name in a constructor"-    assertUnique dbFieldName fields "db field name in a constructor"-    forM_ fields $ \fdef -> assertSpaceFree (exprName fdef) "field expr name"-    case filter (\(PSUniqueDef _ cfields) -> null cfields) $ thConstrUniques cdef of+    assertUnique thExprName fields "expr field name in a constructor"+    assertUnique thDbFieldName fields "db field name in a constructor"+    mapM_ validateField fields+    case filter (\(THUniqueDef _ _ uFields) -> null uFields) $ thConstrUniques cdef of       [] -> return ()       ys -> fail $ "Constraints must have at least one field: " ++ show ys     when (isNothing (thDbAutoKeyName cdef) /= isNothing (thAutoKey def)) $-      fail $ "Presence of autokey definitions should be the same in entity and constructors definitions " ++ show (dataName def)+      fail $ "Presence of autokey definitions should be the same in entity and constructors definitions " ++ show (thDataName def)          -- check that unique keys = [] for multiple constructor datatype   if length constrs > 1 && not (null $ thUniqueKeys def)-    then fail $ "Unique keys may exist only for datatypes with single constructor: " ++ show (dataName def)+    then fail $ "Unique keys may exist only for datatypes with single constructor: " ++ show (thDataName def)     else -- check that all unique keys reference existing uniques-         let uniqueNames = map psUniqueName $ thConstrUniques $ head constrs+         let uniqueNames = map thUniqueName $ thConstrUniques $ head constrs          in  forM_ (thUniqueKeys def) $ \cKey -> unless (thUniqueKeyName cKey `elem` uniqueNames) $-             fail $ "Unique key mentions unknown unique: " ++ thUniqueKeyName cKey ++ " in datatype " ++ show (dataName def)+             fail $ "Unique key mentions unknown unique: " ++ thUniqueKeyName cKey ++ " in datatype " ++ show (thDataName def)   -- check that if unique keys = [] there is auto key   when (null (thUniqueKeys def) && isNothing (thAutoKey def)) $-    fail $ "A datatype must have either an auto key or unique keys: " ++ show (dataName def)+    fail $ "A datatype must have either an auto key or unique keys: " ++ show (thDataName def)   -- check that only one of the keys is default   let defaults = maybe False thAutoKeyIsDef (thAutoKey def) : map thUniqueKeyIsDef (thUniqueKeys def)   when (length (filter id defaults) /= 1) $-    fail $ "A datatype must have exactly one default key: " ++ show (dataName def)+    fail $ "A datatype must have exactly one default key: " ++ show (thDataName def)   return def+  +validateField :: THFieldDef -> Either String ()+validateField fDef = do+  assertSpaceFree (thExprName fDef) "field expr name"+  when (isJust (thDbTypeName fDef) && isJust (thEmbeddedDef fDef)) $+    fail $ "A field may not have both type and embeddedType: " ++ show (thFieldName fDef)  validateEmbedded :: THEmbeddedDef -> Either String THEmbeddedDef validateEmbedded def = do-  let fields = embeddedFields def-  assertUnique exprName fields "expr field name in an embedded datatype"-  assertUnique dbFieldName fields "db field name in an embedded datatype"-  forM_ fields $ \fdef -> assertSpaceFree (exprName fdef) "field expr name"+  let fields = thEmbeddedFields def+  assertUnique thExprName fields "expr field name in an embedded datatype"+  assertUnique thDbFieldName fields "db field name in an embedded datatype"+  mapM_ validateField fields   return def  mkTHEntityDefWith :: NamingStyle -> Dec -> THEntityDef@@ -318,10 +327,10 @@       apply f = f dName' (nameBase name) cNum      mkField :: String -> StrictType -> Int -> THFieldDef-    mkField cName (_, t) fNum = THFieldDef (apply mkNormalFieldName) (apply mkNormalDbFieldName) (apply mkNormalExprFieldName) t Nothing where+    mkField cName (_, t) fNum = THFieldDef (apply mkNormalFieldName) (apply mkNormalDbFieldName) Nothing (apply mkNormalExprFieldName) t Nothing where       apply f = f dName' cName cNum fNum     mkVarField :: String -> VarStrictType -> Int -> THFieldDef-    mkVarField cName (fName, _, t) fNum = THFieldDef fName' (apply mkDbFieldName) (apply mkExprFieldName) t Nothing where+    mkVarField cName (fName, _, t) fNum = THFieldDef fName' (apply mkDbFieldName) Nothing (apply mkExprFieldName) t Nothing where       apply f = f dName' cName cNum fName' fNum       fName' = nameBase fName mkTHEntityDefWith _ _ = error "Only datatypes can be processed"@@ -340,10 +349,10 @@     _ -> error $ "An embedded datatype must have exactly one constructor: " ++ show dName      mkField :: String -> StrictType -> Int -> THFieldDef-  mkField cName' (_, t) fNum = THFieldDef (apply mkNormalFieldName) (apply mkNormalDbFieldName) (mkNormalExprSelectorName dName' cName' fNum) t Nothing where+  mkField cName' (_, t) fNum = THFieldDef (apply mkNormalFieldName) (apply mkNormalDbFieldName) Nothing (mkNormalExprSelectorName dName' cName' fNum) t Nothing where     apply f = f dName' cName' 0 fNum   mkVarField :: String -> VarStrictType -> Int -> THFieldDef-  mkVarField cName' (fName, _, t) fNum = THFieldDef fName' (apply mkDbFieldName) (mkExprSelectorName dName' cName' fName' fNum) t Nothing where+  mkVarField cName' (fName, _, t) fNum = THFieldDef fName' (apply mkDbFieldName) Nothing (mkExprSelectorName dName' cName' fName' fNum) t Nothing where     apply f = f dName' cName' 0 fName' fNum     fName' = nameBase fName mkTHEmbeddedDefWith _ _ = error "Only datatypes can be processed"@@ -360,12 +369,28 @@ -- 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) --+--    \-- 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.org/spec/1.2/spec.html. --  - entity: Settable                   # Mandatory. Entity datatype name@@ -386,33 +411,21 @@ --        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+--          - 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+--            thExprName: 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 --          - name: bar --            dbName: bar---            exprName: BarField+--            thExprName: BarField+--                                       # For some databases \"type: integer\" would be appropriate --        uniques: --          - name: someconstraint+--            type: constraint           # The type can be either \"constraint\" or \"index\" --            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. -- -- @@@ -463,8 +476,20 @@ groundhogFile = quoteFile groundhog  parseDefinitions :: String -> Q Exp-parseDefinitions s = either fail lift result where-  result = decodeEither $ pack s :: Either String PersistDefinitions+parseDefinitions s = do+  result <- runIO $ decodeHelper (Y.decode $ pack s)+  case result of+    Left err -> case err of+      InvalidYaml (Just (Y.YamlParseException problem context mark)) -> fail $ unlines+        [ "YAML parse error: " ++ problem+        , "Context: " ++ context+        , "At line: " ++ show (Y.yamlLine mark)+        , lines s !! Y.yamlLine mark+        , replicate (Y.yamlColumn mark) ' ' ++ "^"+        ]+      _ -> fail $ show err+    Right (Left err) -> fail err+    Right (Right result') -> lift (result' :: PersistDefinitions)  mkEntityDecs :: THEntityDef -> Q [Dec] mkEntityDecs def = do
Database/Groundhog/TH/CodeGen.hs view
@@ -34,22 +34,22 @@ mkEmbeddedPersistFieldInstance :: THEmbeddedDef -> Q [Dec]
 mkEmbeddedPersistFieldInstance def = do
   let types = map extractType $ thEmbeddedTypeParams def
-  let embedded = foldl AppT (ConT (embeddedName def)) types
+  let embedded = foldl AppT (ConT (thEmbeddedName def)) types
 
   persistName' <- do
     v <- newName "v"
     let mkLambda t = [|undefined :: $(forallT (thEmbeddedTypeParams def) (cxt []) [t| $(return embedded) -> $(return t) |]) |]
     let paramNames = foldr1 (\p xs -> [| $p ++ [delim] ++ $xs |] ) $ map (\t -> [| persistName ($(mkLambda t) $(varE v)) |]) types
     let fullEmbeddedName = case null types of
-         True  -> [| $(stringE $ dbEmbeddedName def) |]
-         False -> [| $(stringE $ dbEmbeddedName def) ++ [delim] ++ $(paramNames) |]
+         True  -> [| $(stringE $ thDbEmbeddedName def) |]
+         False -> [| $(stringE $ thDbEmbeddedName def) ++ [delim] ++ $(paramNames) |]
     let body = normalB $ fullEmbeddedName
     let pat = if null types then wildP else varP v
     funD 'persistName $ [ clause [pat] body [] ]
 
   toPersistValues' <- do
-    vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, fieldType f)) $ embeddedFields def
-    let pat = conP (embeddedConstructorName def) $ map (varP . fst) vars
+    vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, thFieldType f)) $ thEmbeddedFields def
+    let pat = conP (thEmbeddedConstructorName def) $ map (varP . fst) vars
     proxy <- newName "p"
     (lastPrims, fields) <- spanM (isPrim . snd) $ reverse vars
     let lastPrims' = map (\(x, _) -> [| toPrimitivePersistValue $(varE proxy) $(varE x) |]) $ reverse $ lastPrims
@@ -70,7 +70,7 @@   fromPersistValues' <- do
     xs <- newName "xs"
     failureName <- newName "failure"
-    (isFailureUsed, body) <- mkFromPersistValues failureName xs (embeddedConstructorName def) (embeddedFields def)
+    (isFailureUsed, body) <- mkFromPersistValues failureName xs (thEmbeddedConstructorName def) (thEmbeddedFields def)
     let failureBody = normalB [| (\a -> fail (failMessage a $(varE xs)) >> return (a, [])) undefined |]
         failureFunc = funD failureName [clause [] failureBody []]
         locals = if isFailureUsed then [failureFunc] else []
@@ -80,18 +80,20 @@     v <- newName "v"
     let mkField fNum f = do
         a <- newName "a"
-        let fname = dbFieldName f
-        let nvar = if hasFreeVars (fieldType f)
-             then let pat = conP (embeddedConstructorName def) $ replicate fNum wildP ++ [varP a] ++ replicate (length (embeddedFields def) - fNum - 1) wildP
-                  in caseE (varE v) $ [match pat (normalB $ varE a) []]
-             else [| undefined :: $(return $ fieldType f) |]
-        case embeddedDef f of
-          Nothing -> [| (fname, dbType $nvar) |]
-          Just e  -> [| (fname, applyEmbeddedDbTypeSettings $(lift e) (dbType $nvar )) |]
+        let fname = thDbFieldName f
+            nvar = if hasFreeVars (thFieldType f)
+              then let pat = conP (thEmbeddedConstructorName def) $ replicate fNum wildP ++ [varP a] ++ replicate (length (thEmbeddedFields def) - fNum - 1) wildP
+                   in caseE (varE v) $ [match pat (normalB $ varE a) []]
+              else [| undefined :: $(return $ thFieldType f) |]
+            typ = case (thEmbeddedDef f, thDbTypeName f) of
+              (Just e, _) -> [| applyEmbeddedDbTypeSettings $(lift e) (dbType $nvar ) |]
+              (_, Just name) -> [| DbOther $(lift name) |]
+              _ -> [| dbType $nvar |]
+        [| (fname, $typ) |]
     let pat = if null $ thEmbeddedTypeParams def then wildP else varP v
-    funD 'dbType $ [ clause [pat] (normalB [| DbEmbedded $ EmbeddedDef False $(listE $ zipWith mkField [0..] (embeddedFields def)) |]) [] ]
+    funD 'dbType $ [ clause [pat] (normalB [| DbEmbedded $ EmbeddedDef False $(listE $ zipWith mkField [0..] (thEmbeddedFields def)) |]) [] ]
 
-  let context = paramsContext (thEmbeddedTypeParams def) (embeddedFields def)
+  let context = paramsContext (thEmbeddedTypeParams def) (thEmbeddedFields def)
   let decs = [persistName', toPersistValues', fromPersistValues', dbType']
   return $ [InstanceD context (AppT (ConT ''PersistField) embedded) decs]
 
@@ -117,7 +119,7 @@     mkArg proxy (fname, t) = isPrim t >>= \isP -> (if isP then [| fromPrimitivePersistValue $(varE proxy) $(varE fname) |] else (varE fname))
     in do
       proxy <- newName "p"
-      vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, fieldType f)) fieldDefs
+      vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, thFieldType f)) fieldDefs
       anyPrim <- liftM or $ mapM (isPrim . snd) vars
       let failure = match wildP (normalB $ varE failureName) []
       let result = foldl (\a f -> appE a $ mkArg proxy f) (conE constrName) vars
@@ -128,7 +130,7 @@ mkPurePersistFieldInstance :: Type -> Name -> [THFieldDef] -> Cxt -> Q [Dec]
 mkPurePersistFieldInstance dataType cName fDefs context = do
   toPurePersistValues' <- do
-    vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, fieldType f)) fDefs
+    vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, thFieldType f)) fDefs
     let pat = conP cName $ map (varP . fst) vars
     proxy <- newName "p"
     let body = mkToPurePersistValues proxy vars
@@ -158,7 +160,7 @@       let failureBody = normalB [| (\a -> error (failMessage a $(varE xs)) `asTypeOf` (a, [])) undefined |]
       failureName <- newName "failure"
       proxy <- newName "p"
-      vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, fieldType f)) fDefs
+      vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, thFieldType f)) fDefs
       let failure = match wildP (normalB $ varE failureName) []
       let result = foldl (\a f -> appE a $ mkArg proxy f) (conE cName) vars
       (isFailureUsed, start) <- goPrim xs vars result failure proxy
@@ -172,17 +174,17 @@ mkEmbeddedPurePersistFieldInstance :: THEmbeddedDef -> Q [Dec]
 mkEmbeddedPurePersistFieldInstance def = do
   let types = map extractType $ thEmbeddedTypeParams def
-  let embedded = foldl AppT (ConT (embeddedName def)) types
-  let fDefs = embeddedFields def
+  let embedded = foldl AppT (ConT (thEmbeddedName def)) types
+  let fDefs = thEmbeddedFields def
   context <- paramsPureContext (thEmbeddedTypeParams def) fDefs
   case context of
     Nothing -> return []
-    Just context' -> mkPurePersistFieldInstance embedded (embeddedConstructorName def) fDefs context'
+    Just context' -> mkPurePersistFieldInstance embedded (thEmbeddedConstructorName def) fDefs context'
 
 mkAutoKeyPersistFieldInstance :: THEntityDef -> Q [Dec]
 mkAutoKeyPersistFieldInstance def = case thAutoKey def of
   Just autoKey -> do
-    let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+    let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
     keyType <- [t| Key $(return entity) BackendSpecific |]
     
     persistName' <- do
@@ -204,7 +206,7 @@ mkAutoKeyPrimitivePersistFieldInstance :: THEntityDef -> Q [Dec]
 mkAutoKeyPrimitivePersistFieldInstance def = case thAutoKey def of
   Just autoKey -> do
-    let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+    let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
     keyType <- [t| Key $(return entity) BackendSpecific |]
     let conName = mkName $ thAutoKeyConstrName autoKey
     toPrim' <- do
@@ -220,7 +222,7 @@ 
 mkUniqueKeysIsUniqueInstances :: THEntityDef -> Q [Dec]
 mkUniqueKeysIsUniqueInstances def = do
-  let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+  let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
   let constr = head $ thConstructors def
   forM (thUniqueKeys def) $ \unique -> do
     uniqKeyType <- [t| Key $(return entity) (Unique $(conT $ mkName $ thUniqueKeyPhantomName unique)) |]
@@ -228,13 +230,13 @@       typ <- conT $ mkName $ thPhantomConstrName constr
       return $ TySynInstD ''UniqueConstr [uniqKeyType] typ
     extractUnique' <- do
-      uniqueFields <- mapM (\f -> newName "x" >>= \x -> return (fieldName f, x)) $ thUniqueKeyFields unique
-      let mkFieldPat f = maybe wildP varP $ lookup (fieldName f) uniqueFields
+      uniqueFields <- mapM (\f -> newName "x" >>= \x -> return (thFieldName f, x)) $ thUniqueKeyFields unique
+      let mkFieldPat f = maybe wildP varP $ lookup (thFieldName f) uniqueFields
       let pat = conP (thConstrName constr) $ map mkFieldPat $ thConstrFields constr
       let body = foldl (\expr f -> [| $expr $(varE $ snd f) |]) (conE $ mkName $ thUniqueKeyConstrName unique) uniqueFields
       funD 'extractUnique [clause [pat] (normalB body) []]
     uniqueNum' <- do
-      let index = findIndex (\u -> thUniqueKeyName unique == psUniqueName u) $ thConstrUniques constr
+      let index = findIndex (\u -> thUniqueKeyName unique == thUniqueName u) $ thConstrUniques constr
       let uNum = maybe (error $ "mkUniqueKeysIsUniqueInstances: cannot find unique definition for unique key " ++ thUniqueKeyName unique) id index
       funD 'uniqueNum [clause [wildP] (normalB [| uNum |]) []]
     let context = paramsContext (thTypeParams def) (thConstructors def >>= thConstrFields)
@@ -242,7 +244,7 @@ 
 mkUniqueKeysEmbeddedInstances :: THEntityDef -> Q [Dec]
 mkUniqueKeysEmbeddedInstances def = do
-  let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+  let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
   liftM concat $ forM (filter thUniqueKeyMakeEmbedded $ thUniqueKeys def) $ \unique -> do
     uniqKeyType <- [t| Key $(return entity) (Unique $(conT $ mkName $ thUniqueKeyPhantomName unique)) |]
     let context = paramsContext (thTypeParams def) (thConstructors def >>= thConstrFields)
@@ -250,7 +252,7 @@   
 mkUniqueKeysPersistFieldInstances :: THEntityDef -> Q [Dec]
 mkUniqueKeysPersistFieldInstances def = do
-  let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+  let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
   forM (thUniqueKeys def) $ \unique -> do
     uniqKeyType <- [t| Key $(return entity) (Unique $(conT $ mkName $ thUniqueKeyPhantomName unique)) |]
 
@@ -263,11 +265,13 @@     dbType' <- do
       a <- newName "a"
       let mkField f = do
-          let fname = dbFieldName f
-          let nvar = [| undefined :: $(return $ fieldType f) |]
-          case embeddedDef f of
-            Nothing -> [| (fname, dbType $nvar) |]
-            Just e  -> [| (fname, applyEmbeddedDbTypeSettings $(lift e) (dbType $nvar )) |]
+          let fname = thDbFieldName f
+              nvar = [| undefined :: $(return $ thFieldType f) |]
+              typ = case (thEmbeddedDef f, thDbTypeName f) of
+                (Just e, _)  -> [| applyEmbeddedDbTypeSettings $(lift e) (dbType $nvar ) |]
+                (_, Just name) -> [| DbOther $(lift name) |]
+                _ -> [| dbType $nvar |]
+          [| (fname, $typ) |]
       let embedded = [| EmbeddedDef False $(listE $ map mkField $ thUniqueKeyFields unique) |]
       let body = [| DbEntity (Just ($embedded, $(lift $ thUniqueKeyName unique))) $ entityDef ((undefined :: Key v a -> v) $(varE a)) |]
       funD 'dbType [clause [varP a] (normalB body) []]
@@ -277,13 +281,13 @@     
 mkUniqueKeysPrimitiveOrPurePersistFieldInstances :: THEntityDef -> Q [Dec]
 mkUniqueKeysPrimitiveOrPurePersistFieldInstances def = do
-  let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+  let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
   liftM concat $ forM (thUniqueKeys def) $ \unique -> do
     uniqKeyType <- [t| Key $(return entity) (Unique $(conT $ mkName $ thUniqueKeyPhantomName unique)) |]
     let context = paramsContext (thTypeParams def) (thConstructors def >>= thConstrFields)
     let conName = mkName $ thUniqueKeyConstrName unique
     isUniquePrim <- if (length $ thUniqueKeyFields unique) == 1
-      then isPrim $ fieldType $ head $ thUniqueKeyFields unique
+      then isPrim $ thFieldType $ head $ thUniqueKeyFields unique
       else return False
     if isUniquePrim
       then do
@@ -298,7 +302,7 @@ 
 mkKeyEqShowInstances :: THEntityDef -> Q [Dec]
 mkKeyEqShowInstances def = do
-  let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+  let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
   let mkShowInstance typ cName fieldsNum = do
       showsPrec' <- do
         p <- newName "p"
@@ -339,19 +343,19 @@ mkEmbeddedInstance :: THEmbeddedDef -> Q [Dec]
 mkEmbeddedInstance def = do
   let types = map extractType $ thEmbeddedTypeParams def
-  let embedded = foldl AppT (ConT (embeddedName def)) types
-  let context = paramsContext (thEmbeddedTypeParams def) (embeddedFields def)
-  mkEmbeddedInstance' embedded (embeddedFields def) context
+  let embedded = foldl AppT (ConT (thEmbeddedName def)) types
+  let context = paramsContext (thEmbeddedTypeParams def) (thEmbeddedFields def)
+  mkEmbeddedInstance' embedded (thEmbeddedFields def) context
   
 mkEmbeddedInstance' :: Type -> [THFieldDef] -> Cxt -> Q [Dec]
 mkEmbeddedInstance' dataType fDefs context = do
   selector' <- do
     fParam <- newName "f"
-    let mkField field = ForallC [] ([EqualP (VarT fParam) (fieldType field)]) $ NormalC (mkName $ exprName field) []
+    let mkField field = ForallC [] ([EqualP (VarT fParam) (thFieldType field)]) $ NormalC (mkName $ thExprName field) []
     return $ DataInstD [] ''Selector [dataType, VarT fParam] (map mkField fDefs) []
 
   selectorNum' <- do
-    let mkClause fNum field = clause [conP (mkName $ exprName field) []] (normalB $ lift fNum) []
+    let mkClause fNum field = clause [conP (mkName $ thExprName field) []] (normalB $ lift fNum) []
     let clauses = zipWith mkClause [0 :: Int ..] fDefs
     funD 'selectorNum clauses
 
@@ -360,7 +364,7 @@ 
 mkEntityPhantomConstructors :: THEntityDef -> Q [Dec]
 mkEntityPhantomConstructors def = do
-  let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+  let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
   forM (thConstructors def) $ \c -> do
     v <- newName "v"
     let name = mkName $ thPhantomConstrName c
@@ -372,12 +376,12 @@ mkEntityPhantomConstructorInstances def = sequence $ zipWith f [0..] $ thConstructors def where
   f :: Int -> THConstructorDef -> Q Dec
   f cNum c = instanceD (cxt []) (appT (conT ''Constructor) (conT $ mkName $ thPhantomConstrName c)) [phantomConstrName', phantomConstrNum'] where
-    phantomConstrName' = funD 'phantomConstrName [clause [wildP] (normalB $ stringE $ dbConstrName c) []]
+    phantomConstrName' = funD 'phantomConstrName [clause [wildP] (normalB $ stringE $ thDbConstrName c) []]
     phantomConstrNum' = funD 'phantomConstrNum [clause [wildP] (normalB $ [| cNum |]) []]
 
 mkEntityUniqueKeysPhantoms :: THEntityDef -> Q [Dec]
 mkEntityUniqueKeysPhantoms def = do
-  let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+  let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
   forM (thUniqueKeys def) $ \u -> do
     v <- newName "v"
     let name = mkName $ thUniqueKeyPhantomName u
@@ -387,7 +391,7 @@     
 mkPersistEntityInstance :: THEntityDef -> Q [Dec]
 mkPersistEntityInstance def = do
-  let entity = foldl AppT (ConT (dataName def)) $ map extractType $ thTypeParams def
+  let entity = foldl AppT (ConT (thDataName def)) $ map extractType $ thTypeParams def
 
   key' <- do
     uParam <- newName "u"
@@ -399,11 +403,9 @@     uniques <- forM (thUniqueKeys def) $ \unique -> do
       let cDef = head $ thConstructors def
       uniqType <- [t| Unique $(conT $ mkName $ thUniqueKeyPhantomName unique) |]
-      let uniqFieldNames = case filter ((== thUniqueKeyName unique) . psUniqueName) $ thConstrUniques cDef of
-            [a] -> psUniqueFields a
-            _   -> error $ "Unique key must correspond to one unique definition: " ++ thUniqueKeyName unique
-      let uniqFields = concat $ flip map uniqFieldNames $ \name -> (filter ((== name) . fieldName) $ thConstrFields cDef)
-      let uniqFields' = map (\f -> (NotStrict, fieldType f)) uniqFields
+      let uniqFieldNames = thUniqueFields $ findOne "unique" thUniqueKeyName thUniqueName unique $ thConstrUniques cDef
+      let uniqFields = concat $ flip map uniqFieldNames $ \name -> (filter ((== name) . thFieldName) $ thConstrFields cDef)
+      let uniqFields' = map (\f -> (NotStrict, thFieldType f)) uniqFields
       return $ ForallC [] [EqualP (VarT uParam) uniqType] $ NormalC (mkName $ thUniqueKeyConstrName unique) uniqFields'
     return $ DataInstD [] ''Key [entity, VarT uParam] (autoKey ++ uniques) []
 
@@ -424,7 +426,7 @@   fields' <- do
     cParam <- newName "c"
     fParam <- newName "f"
-    let mkField name field = ForallC [] [EqualP (VarT cParam) (ConT name), EqualP (VarT fParam) (fieldType field)] $ NormalC (mkName $ exprName field) []
+    let mkField name field = ForallC [] [EqualP (VarT cParam) (ConT name), EqualP (VarT fParam) (thFieldType field)] $ NormalC (mkName $ thExprName field) []
     let f cdef = map (mkField $ mkName $ thPhantomConstrName cdef) $ thConstrFields cdef
     let constrs = concatMap f $ thConstructors def
     return $ DataInstD [] ''Field [entity, VarT cParam, VarT fParam] constrs []
@@ -436,34 +438,36 @@     let typeParams' = listE $ map (\t -> [| dbType ($(mkLambda t) $(varE v)) |]) types
     let mkField c fNum f = do
         a <- newName "a"
-        let fname = dbFieldName f
-        let nvar = if hasFreeVars (fieldType f)
-             then let pat = conP (thConstrName c) $ replicate fNum wildP ++ [varP a] ++ replicate (length (thConstrFields c) - fNum - 1) wildP
-                      wildClause = if length (thConstructors def) > 1 then [match wildP (normalB [| undefined |]) []] else []
-                  in caseE (varE v) $ [match pat (normalB $ varE a) []] ++ wildClause
-             else [| undefined :: $(return $ fieldType f) |]
-        case embeddedDef f of
-          Nothing -> [| (fname, dbType $nvar) |]
-          Just e  -> [| (fname, applyEmbeddedDbTypeSettings $(lift e) (dbType $nvar )) |]
+        let fname = thDbFieldName f
+            nvar = if hasFreeVars (thFieldType f)
+              then let pat = conP (thConstrName c) $ replicate fNum wildP ++ [varP a] ++ replicate (length (thConstrFields c) - fNum - 1) wildP
+                       wildClause = if length (thConstructors def) > 1 then [match wildP (normalB [| undefined |]) []] else []
+                   in caseE (varE v) $ [match pat (normalB $ varE a) []] ++ wildClause
+              else [| undefined :: $(return $ thFieldType f) |]
+            typ = case (thEmbeddedDef f, thDbTypeName f) of
+              (Just e, _)  -> [| applyEmbeddedDbTypeSettings $(lift e) (dbType $nvar ) |]
+              (_, Just name) -> [| DbOther $(lift name) |]
+              _ -> [| dbType $nvar |]
+        [| (fname, $typ) |]
     let constrs = listE $ zipWith mkConstructorDef [0..] $ thConstructors def
         mkConstructorDef cNum c@(THConstructorDef _ _ name keyName params conss) = [| ConstructorDef cNum name keyName $(listE $ map snd fields) $(listE $ map mkConstraint conss) |] where
-          fields = zipWith (\i f -> (fieldName f, mkField c i f)) [0..] params
-          mkConstraint (PSUniqueDef uName uFields) = [| UniqueDef uName $(listE $ map getField uFields) |]
+          fields = zipWith (\i f -> (thFieldName f, mkField c i f)) [0..] params
+          mkConstraint (THUniqueDef uName uType uFields) = [| UniqueDef uName uType $(listE $ map getField uFields) |]
           getField fName = case lookup fName fields of
             Just f -> f
             Nothing -> error $ "Field name " ++ show fName ++ " declared in unique not found"
     
     let paramNames = foldr1 (\p xs -> [| $p ++ [delim] ++ $xs |] ) $ map (\t -> [| persistName ($(mkLambda t) $(varE v)) |]) types
     let fullEntityName = case null types of
-         True  -> [| $(stringE $ dbEntityName def) |]
-         False -> [| $(stringE $ dbEntityName def) ++ [delim] ++ $(paramNames) |]
+         True  -> [| $(stringE $ thDbEntityName def) |]
+         False -> [| $(stringE $ thDbEntityName def) ++ [delim] ++ $(paramNames) |]
 
     let body = normalB [| EntityDef $fullEntityName $typeParams' $constrs |]
     let pat = if null $ thTypeParams def then wildP else varP v
     funD 'entityDef $ [ clause [pat] body [] ]
 
   toEntityPersistValues' <- liftM (FunD 'toEntityPersistValues) $ forM (zip [0..] $ thConstructors def) $ \(cNum, c) -> do
-    vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, fieldType f)) $ thConstrFields c
+    vars <- mapM (\f -> newName "x" >>= \fname -> return (fname, thFieldType f)) $ thConstrFields c
     let pat = conP (thConstrName c) $ map (varP . fst) vars
     proxy <- newName "p"
     (lastPrims, fields) <- spanM (isPrim . snd) $ reverse vars
@@ -501,25 +505,26 @@     mkClause cNum cdef | not (hasConstraints cdef) = clause [wildP, conP (thConstrName cdef) pats] (normalB [| (cNum, []) |]) [] where
       pats = map (const wildP) $ thConstrFields cdef
     mkClause cNum cdef = do
-      let allConstrainedFields = concatMap psUniqueFields $ thConstrUniques cdef
-      vars <- mapM (\f -> newName "x" >>= \x -> return $ if fieldName f `elem` allConstrainedFields then Just (x, fieldType f) else Nothing) $ thConstrFields cdef
+      let allConstrainedFields = concatMap thUniqueFields $ thConstrUniques cdef
+      vars <- mapM (\f -> newName "x" >>= \x -> return $ if thFieldName f `elem` allConstrainedFields then Just (x, thFieldType f) else Nothing) $ thConstrFields cdef
       let pat = conP (thConstrName cdef) $ map (maybe wildP (varP . fst)) vars
       proxy <- newName "p"
-      let body = normalB $ [| (cNum, $(listE $ map (\(PSUniqueDef uName fnames) -> [| (uName, $result []) |] ) $ thConstrUniques cdef)) |]
+      let body = normalB $ [| (cNum, $(listE $ map (\(THUniqueDef uName _ fnames) -> [| (uName, $result) |] ) $ thConstrUniques cdef)) |]
           result = mkToPurePersistValues proxy (catMaybes vars)
       clause [varP proxy, pat] body []
     in funD 'getUniques clauses
 
   entityFieldChain' <- let
-    fieldNames = thConstructors def >>= thConstrFields
-    clauses = map (\f -> mkChain f >>= \(fArg, body) -> clause [asP fArg $ conP (mkName $ exprName f) []] (normalB body) []) fieldNames
+    thFieldNames = thConstructors def >>= thConstrFields
+    clauses = map (\f -> mkChain f >>= \(fArg, body) -> clause [asP fArg $ conP (mkName $ thExprName f) []] (normalB body) []) thFieldNames
     mkChain f = do
         fArg <- newName "f"
         let nvar = [| (undefined :: Field v c a -> a) $(varE fArg) |]
-        let typ = case embeddedDef f of
-              Nothing -> [| dbType $nvar |]
-              Just e  -> [| applyEmbeddedDbTypeSettings $(lift e) (dbType $nvar ) |]
-        let body = [| (($(lift $ dbFieldName f), $typ), []) |]
+            typ = case (thEmbeddedDef f, thDbTypeName f) of
+              (Just e, _)  -> [| applyEmbeddedDbTypeSettings $(lift e) (dbType $nvar ) |]
+              (_, Just name) -> [| DbOther $(lift name) |]
+              _ -> [| dbType $nvar |]
+        let body = [| (($(lift $ thDbFieldName f), $typ), []) |]
         return (fArg, body)
     in funD 'entityFieldChain clauses
 
@@ -545,7 +550,7 @@ mkEntityPersistFieldInstance :: THEntityDef -> Q [Dec]
 mkEntityPersistFieldInstance def = do
   let types = map extractType $ thTypeParams def
-  let entity = foldl AppT (ConT (dataName def)) types
+  let entity = foldl AppT (ConT (thDataName def)) types
   
   persistName' <- do
     v <- newName "v"
@@ -553,8 +558,8 @@     
     let paramNames = foldr1 (\p xs -> [| $p ++ [delim] ++ $xs |] ) $ map (\t -> [| persistName ($(mkLambda t) $(varE v)) |]) types
     let fullEntityName = case null types of
-         True  -> [| $(stringE $ dbEntityName def) |]
-         False -> [| $(stringE $ dbEntityName def) ++ [delim] ++ $(paramNames) |]
+         True  -> [| $(stringE $ thDbEntityName def) |]
+         False -> [| $(stringE $ thDbEntityName def) ++ [delim] ++ $(paramNames) |]
     let body = normalB $ fullEntityName
     let pat = if null types then wildP else varP v
     funD 'persistName $ [ clause [pat] body [] ]
@@ -601,13 +606,13 @@       Right k -> ([| toSinglePersistValueUnique $u |], [| fromSinglePersistValueUnique $u |]) where
         u = conE $ mkName $ thUniqueKeyPhantomName k
     types = map extractType $ thTypeParams def
-    entity = foldl AppT (ConT (dataName def)) types
+    entity = foldl AppT (ConT (thDataName def)) types
     context = paramsContext (thTypeParams def) (thConstructors def >>= thConstrFields)
 
 mkEntityNeverNullInstance :: THEntityDef -> Q [Dec]
 mkEntityNeverNullInstance def = do
   let types = map extractType $ thTypeParams def
-  let entity = foldl AppT (ConT (dataName def)) types
+  let entity = foldl AppT (ConT (thDataName def)) types
   let context = paramsContext (thTypeParams def) (thConstructors def >>= thConstrFields)
   isOne <- isDefaultKeyOneColumn def
   return $ if isOne
@@ -617,8 +622,8 @@ mkMigrateFunction :: String -> [THEntityDef] -> Q [Dec]
 mkMigrateFunction name defs = do
   let (normal, polymorhpic) = partition (null . thTypeParams) defs
-  forM_ polymorhpic $ \def -> report False $ "Datatype " ++ show (dataName def) ++ " will not be migrated automatically by function " ++ name ++ " because it has type parameters"
-  let body = doE $ map (\def -> noBindS [| migrate (undefined :: $(conT $ dataName def)) |]) normal
+  forM_ polymorhpic $ \def -> report False $ "Datatype " ++ show (thDataName def) ++ " will not be migrated automatically by function " ++ name ++ " because it has type parameters"
+  let body = doE $ map (\def -> noBindS [| migrate (undefined :: $(conT $ thDataName def)) |]) normal
   sig <- sigD (mkName name) [t| PersistBackend m => Migration m |]
   func <- funD (mkName name) [clause [] (normalB body) []]
   return [sig, func]
@@ -626,7 +631,7 @@ isDefaultKeyOneColumn :: THEntityDef -> Q Bool
 isDefaultKeyOneColumn def = either (const $ return True) checkUnique $ getDefaultKey def where
   checkUnique unique = if (length $ thUniqueKeyFields unique) == 1
-    then isPrim $ fieldType $ head $ thUniqueKeyFields unique
+    then isPrim $ thFieldType $ head $ thUniqueKeyFields unique
     else return False
 
 getDefaultKey :: THEntityDef -> Either THAutoKeyDef THUniqueKeyDef
@@ -642,13 +647,13 @@   -- all datatype fields also must be instances of PersistField
   -- if Maybe is applied to a type param, the param must be also an instance of NeverNull
   -- so that (Maybe param) is an instance of PersistField
-  maybys = nub $ fields >>= insideMaybe . fieldType
+  maybys = nub $ fields >>= insideMaybe . thFieldType
 
 paramsPureContext :: [TyVarBndr] -> [THFieldDef] -> Q (Maybe Cxt)
 paramsPureContext types fields = do
   let isValidType (VarT _) = return True
       isValidType t = isPrim t
-  invalid <- filterM (liftM not . isValidType . fieldType) fields
+  invalid <- filterM (liftM not . isValidType . thFieldType) fields
   return $ case invalid of
     [] -> Just $ classPred ''PurePersistField params ++ classPred ''PrimitivePersistField maybys ++ classPred ''NeverNull maybys where
           params = map extractType types
@@ -656,7 +661,7 @@           -- all datatype fields also must be instances of PersistField
           -- if Maybe is applied to a type param, the param must be also an instance of NeverNull
           -- so that (Maybe param) is an instance of PersistField
-          maybys = nub $ fields >>= insideMaybe . fieldType
+          maybys = nub $ fields >>= insideMaybe . thFieldType
     _  -> Nothing
 
 extractType :: TyVarBndr -> Type
Database/Groundhog/TH/Settings.hs view
@@ -7,6 +7,7 @@   , THEmbeddedDef(..)
   , THConstructorDef(..)
   , THFieldDef(..)
+  , THUniqueDef(..)
   , THUniqueKeyDef(..)
   , THAutoKeyDef(..)
   , PSEntityDef(..)
@@ -19,6 +20,7 @@   , PSAutoKeyDef(..)
   ) where
 
+import Database.Groundhog.Core (UniqueType(..))
 import Database.Groundhog.Generic (PSEmbeddedFieldDef(..))
 import Language.Haskell.TH
 import Language.Haskell.TH.Syntax (Lift(..))
@@ -31,8 +33,8 @@ -- data SomeData a = U1 { foo :: Int} | U2 { bar :: Maybe String, asc :: Int64, add :: a} | U3 deriving (Show, Eq)
 
 data THEntityDef = THEntityDef {
-    dataName :: Name -- SomeData
-  , dbEntityName :: String  -- SQLSomeData
+    thDataName :: Name -- SomeData
+  , thDbEntityName :: String  -- SQLSomeData
   , thAutoKey :: Maybe THAutoKeyDef
   , thUniqueKeys :: [THUniqueKeyDef]
   , thTypeParams :: [TyVarBndr]
@@ -45,30 +47,37 @@ } deriving Show
 
 data THEmbeddedDef = THEmbeddedDef {
-    embeddedName :: Name
-  , embeddedConstructorName :: Name
-  , dbEmbeddedName :: String -- used only to set polymorphic part of name of its container
+    thEmbeddedName :: Name
+  , thEmbeddedConstructorName :: Name
+  , thDbEmbeddedName :: String -- used only to set polymorphic part of name of its container
   , thEmbeddedTypeParams :: [TyVarBndr]
-  , embeddedFields :: [THFieldDef]
+  , thEmbeddedFields :: [THFieldDef]
 } deriving Show
 
 data THConstructorDef = THConstructorDef {
     thConstrName    :: Name -- U2
   , thPhantomConstrName :: String -- U2Constructor
-  , dbConstrName    :: String -- SQLU2
+  , thDbConstrName    :: String -- SQLU2
   , thDbAutoKeyName :: Maybe String -- u2_id
   , thConstrFields  :: [THFieldDef]
-  , thConstrUniques :: [PSUniqueDef]
+  , thConstrUniques :: [THUniqueDef]
 } deriving Show
 
 data THFieldDef = THFieldDef {
-    fieldName :: String -- bar
-  , dbFieldName :: String -- SQLbar
-  , exprName :: String -- BarField
-  , fieldType :: Type
-  , embeddedDef :: Maybe [PSEmbeddedFieldDef]
+    thFieldName :: String -- bar
+  , thDbFieldName :: String -- SQLbar
+  , thDbTypeName :: Maybe String -- inet, NUMERIC(5, 2), VARCHAR(50)
+  , thExprName :: String -- BarField
+  , thFieldType :: Type
+  , thEmbeddedDef :: Maybe [PSEmbeddedFieldDef]
 } deriving Show
 
+data THUniqueDef = THUniqueDef {
+    thUniqueName :: String
+  , thUniqueType :: UniqueType
+  , thUniqueFields :: [String]
+} deriving Show
+
 data THUniqueKeyDef = THUniqueKeyDef {
     thUniqueKeyName :: String
   , thUniqueKeyPhantomName :: String
@@ -105,12 +114,14 @@ data PSFieldDef = PSFieldDef {
     psFieldName :: String -- bar
   , psDbFieldName :: Maybe String -- SQLbar
+  , psDbTypeName :: Maybe String -- inet, NUMERIC(5,2), VARCHAR(50)
   , psExprName :: Maybe String -- BarField
   , psEmbeddedDef :: Maybe [PSEmbeddedFieldDef]
 } deriving Show
 
 data PSUniqueDef = PSUniqueDef {
     psUniqueName :: String
+  , psUniqueType :: Maybe UniqueType
   , psUniqueFields :: [String]
 } deriving Show
 
@@ -142,13 +153,17 @@   lift (PSConstructorDef {..}) = [| PSConstructorDef $(lift psConstrName) $(lift psPhantomConstrName) $(lift psDbConstrName) $(lift psDbAutoKeyName) $(lift psConstrFields) $(lift psConstrUniques) |]
 
 instance Lift PSUniqueDef where
-  lift (PSUniqueDef name fields) = [| PSUniqueDef $(lift name) $(lift fields) |]
+  lift (PSUniqueDef name typ fields) = [| PSUniqueDef $(lift name) $(lift typ) $(lift fields) |]
 
+instance Lift UniqueType where
+  lift UniqueConstraint = [| UniqueConstraint |]
+  lift UniqueIndex = [| UniqueIndex |]
+
 instance Lift PSFieldDef where
-  lift (PSFieldDef {..}) = [| PSFieldDef $(lift psFieldName) $(lift psDbFieldName) $(lift psExprName) $(lift psEmbeddedDef) |]
+  lift (PSFieldDef {..}) = [| PSFieldDef $(lift psFieldName) $(lift psDbFieldName) $(lift psDbTypeName) $(lift psExprName) $(lift psEmbeddedDef) |]
 
 instance Lift PSEmbeddedFieldDef where
-  lift (PSEmbeddedFieldDef {..}) = [| PSEmbeddedFieldDef $(lift psEmbeddedFieldName) $(lift psDbEmbeddedFieldName) $(lift psSubEmbedded) |]
+  lift (PSEmbeddedFieldDef {..}) = [| PSEmbeddedFieldDef $(lift psEmbeddedFieldName) $(lift psDbEmbeddedFieldName) $(lift psDbEmbeddedTypeName) $(lift psSubEmbedded) |]
 
 instance Lift PSUniqueKeyDef where
   lift (PSUniqueKeyDef {..}) = [| PSUniqueKeyDef $(lift psUniqueKeyName) $(lift psUniqueKeyPhantomName) $(lift psUniqueKeyConstrName) $(lift psUniqueKeyDbName) $(lift psUniqueKeyFields) $(lift psUniqueKeyMakeEmbedded) $(lift psUniqueKeyIsDef) |]
@@ -199,15 +214,23 @@   parseJSON _          = mzero
 
 instance FromJSON PSUniqueDef where
-  parseJSON (Object v) = PSUniqueDef <$> v .: "name" <*> v .: "fields"
+  parseJSON (Object v) = PSUniqueDef <$> v .: "name" <*> v .:? "type" <*> v .: "fields"
   parseJSON _          = mzero
 
+instance FromJSON UniqueType where
+  parseJSON o = do
+    x <- parseJSON o
+    case (x :: String) of
+      "constraint" -> return UniqueConstraint
+      "index" -> return UniqueIndex
+      _ -> fail "parseJSON: UniqueType must be either \"constraint\" or \"index\""
+
 instance FromJSON PSFieldDef where
-  parseJSON (Object v) = PSFieldDef <$> v .: "name" <*> v .:? "dbName" <*> v .:? "exprName" <*> v .:? "embeddedType"
+  parseJSON (Object v) = PSFieldDef <$> v .: "name" <*> v .:? "dbName" <*> v .:? "type" <*> v .:? "exprName" <*> v .:? "embeddedType"
   parseJSON _          = mzero
 
 instance FromJSON PSEmbeddedFieldDef where
-  parseJSON (Object v) = PSEmbeddedFieldDef <$> v .: "name" <*> v .:? "dbName" <*> v .:? "embeddedType"
+  parseJSON (Object v) = PSEmbeddedFieldDef <$> v .: "name" <*> v .:? "dbName" <*> v .:? "type" <*> v .:? "embeddedType"
   parseJSON _          = mzero
 
 instance FromJSON PSUniqueKeyDef where
groundhog-th.cabal view
@@ -1,5 +1,5 @@ name:            groundhog-th-version:         0.1.0.3+version:         0.2.0 license:         BSD3 license-file:    LICENSE author:          Boris Lykah <lykahb@gmail.com>@@ -14,11 +14,11 @@ library     build-depends:   base                     >= 4         && < 5                    , bytestring               >= 0.9-                   , groundhog                >= 0.1.0     && < 0.2.0+                   , groundhog                >= 0.2.0     && < 0.3.0                    , template-haskell                    , time                     >= 1.1.4                    , containers               >= 0.2-                   , yaml                     >= 0.6.1+                   , yaml                     >= 0.8.1     exposed-modules: Database.Groundhog.TH                      Database.Groundhog.TH.Settings                      Database.Groundhog.TH.CodeGen