[Haskell-cafe] Using template haskell to create pseudo columns

Justin Bailey jgbailey at gmail.com
Mon Feb 25 18:01:12 EST 2008


Adding pseudo columns to a projection is cumbersome, to say the list.
For example, to add a field named "hidden" to a query I have to write:

  data Hide = Hide
  instance FieldTag Hide where
    fieldName _ = "hide"

  hideField = mkAttr Hide

I wrote a little Template haskell that reduces this to:

  $(mkField "hide")

If you want to customize the name of the column in the generated SQL,
another function is used:

  $(mkFieldWithName "NumPullingParts" "num_pulling_parts")

The code is below. Some questions:

  * Does the code look reasonable and useful?
  * Would the haskelldb maintainers want to introduce a dependency on
template haskell to haskelldb for this kind of code?
  * Otherwise, would an "extensions" package make sense?

If the reaction is positive, I'll work on extending this for a patch.
My heartfelt thanks to Bulat for his excellent template haskell
tutorials. I really wish that library had better documentation!

Justin

mkField :: String -> Q [Dec]
mkField [] = error "Can't generate field from an empty string."
mkField f =
  let fieldType = if isUpper (head f) then f else (toUpper (head f)) : tail f
      colName = if isLower (head f) then f else (toLower (head f)) : tail f
  in mkFieldWithName fieldType colName

-- ^ Creates a compile time field declaration using the given
-- arguments for the type and column name of the field. The fieldType argument
-- is used to produce the "<field name>Field" function which can be used to
-- add the field to a projection.
--
-- Note that an error will occur if fieldType is not a proper
type/constructor name.
mkFieldWithName :: String -> String -> Q [Dec]
mkFieldWithName [] _ = error "Can't create a field with an empty type."
mkFieldWithName _ [] = error "Can't create a field with an empty column name."
mkFieldWithName fieldType colName =
  let ty = mkName fieldType
      fieldName = toLower (head fieldType) : tail fieldType
      fieldD = [DataD [] ty [] [NormalC ty []] []]
      fieldI = [InstanceD [] (AppT (ConT (mkName
"Database.HaskellDB.HDBRec.FieldTag"))
                                   (ConT ty)) [FunD (mkName
"fieldName") [Clause [WildP]
                                                      (NormalB (LitE
(StringL colName))) []]]]
      fieldF = [ValD (VarP (mkName (fieldName ++ "Field"))) (NormalB
(AppE (VarE (mkName "Database.HaskellDB.DBLayout.mkAttr"))
                                                              (ConE ty))) []]
  in return (fieldD ++ fieldI ++ fieldF)


More information about the Haskell-Cafe mailing list