[Haskell-cafe] Using template haskell to create pseudo columns
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:
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!
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
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
(ConT ty)) [FunD (mkName
"fieldName") [Clause [WildP]
(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