How to Serialize a Type to specified database columns - haskell

I am using postgresql-simple in a haskell application, and i want to be able to serialize a data type to a row in my database that doesn't have a 1 to 1 mapping of the record fields used in the data type because i am using them in other data types. (I'm Fairly New to Haskell but I think this involves using the Identifier data constructor).
Example I have a database table Users with the following columns: user_id, email, name, password, address, phone_number
now I have a type with the following format:
data UserDetails = UserDetails {
user_id :: Int,
email :: Text,
phone_number :: Maybe (Text),
password :: Text,
name :: Maybe (Text),
address :: Maybe (Text),
} deriving (Show, Generic, FromRow)
And i can have a generic ToRow implemented for this type no problem since the record fields are the same as the column names, but I have another type that i want to generate a ToRow instance for which is:
data UserEditDetails = UserEditDetails {
ued_email :: Maybe (Email),
ued_phone_number :: Maybe (Text),
ued_address :: Maybe (Text),
ued_name :: Maybe (Text),
} deriving (Show, Generic)
how would i implement a ToRow instance of this type or more generally how can i write a ToRow instance like the following pseudo code
instance ToRow UserEditDetails where
toRow a = (columnname, ued_email a)... etc
hopefully it has a function similar to Aeson where you can easily write something like:
instance ToJSON Login where
toJSON = genericToJSON defaultOptions { fieldLabelModifier = drop 4 }
but i havent found this.

postgresql-simple doesn't pay any attention to database column names. It just expects the count and order of columns serialized or deserialized by the ToRow/FromRow instances will match the count and order of columns in the SQL query. You can use the generic instance for ToRow UserEditDetails as long as the query you're feeding it to matches the four columns in the right order. For example, if you have the following definition and generic ToRow instance:
data UserEditDetails = UserEditDetails
{ ued_email :: Maybe Text
, ued_phone_number :: Maybe Text
, ued_address :: Maybe Text
, ued_name :: Maybe Text
} deriving (Show, Generic, ToRow)
then I believe the following query will work fine:
do let q = "update user_table set email=?, phone_number=?, address=?, name=? "
++ "where user_id=?"
execute conn q $ (UserEditDetails
(Just "me#example.invalid")
(Just "555-1212")
(Just "123 Fake Street")
(Just "Bob Jones"))
:. Only (15 :: Int) -- user_id 15
Note that the generic instances from FromRow and ToRow are equivalent to:
instance ToRow UserEditDetails where
toRow (UserEditDetails a b c d) = [toField a, toField b, toField c, toField d]
instance FromRow UserEditDetails where
fromRow = UserEditDetails <$> field <*> field <*> field <*> field
The fields are anonymous and there's no place to give specific database columns anyway.

Related

How to elegantly avoid "Ambiguous type variable" when using Haskell type classes

I want to write a simple framework that deals with persisting entities.
The idea is to have an Entity type class and to provide generic persistence operations like
storeEntity :: (Entity a) => a -> IO ()
retrieveEntity :: (Entity a) => Integer -> IO a
publishEntity :: (Entity a) => a -> IO ()
Actual data types are instance of that Entity type class.
Even though the persistence operations are generic and don't need any information about the concrete data types You have to provide a type annotation at the call site to make GHC happy, like in:
main = do
let user1 = User 1 "Thomas" "Meier" "tm#meier.com"
storeEntity user1
user2 <- retrieveEntity 1 :: IO User -- how to avoid this type annotation?
publishEntity user2
Is there any way to avoid this kind of call site annotations?
I know that I don't need these annotations if the compiler can deduce the actual type from the context of the usage. So for example the following code works fine:
main = do
let user1 = User 1 "Thomas" "Meier" "tm#meier.com"
storeEntity user1
user2 <- retrieveEntity 1
if user1 == user2
then publishEntity user2
else fail "retrieve of data failed"
But I would like to be able to chain the polymorphic actions like so:
main = do
let user1 = User 1 "Heinz" "Meier" "hm#meier.com"
storeEntity user1
-- unfortunately the next line does not compile
retrieveEntity 1 >>= publishEntity
-- but with a type annotation it works:
(retrieveEntity 1 :: IO User) >>= publishEntity
But having a type annotation here breaks the elegance of the polymorphism...
For completeness sake I've included the full source code:
{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}
module Example where
import GHC.Generics
import Data.Aeson
-- | Entity type class
class (ToJSON e, FromJSON e, Eq e, Show e) => Entity e where
getId :: e -> Integer
-- | a user entity
data User = User {
userId :: Integer
, firstName :: String
, lastName :: String
, email :: String
} deriving (Show, Eq, Generic, ToJSON, FromJSON)
instance Entity User where
getId = userId
-- | load persistent entity of type a and identified by id
retrieveEntity :: (Entity a) => Integer -> IO a
retrieveEntity id = do
-- compute file path based on id
let jsonFileName = getPath id
-- parse entity from JSON file
eitherEntity <- eitherDecodeFileStrict jsonFileName
case eitherEntity of
Left msg -> fail msg
Right e -> return e
-- | store persistent entity of type a to a json file
storeEntity :: (Entity a) => a -> IO ()
storeEntity entity = do
-- compute file path based on entity id
let jsonFileName = getPath (getId entity)
-- serialize entity as JSON and write to file
encodeFile jsonFileName entity
-- | compute path of data file based on id
getPath :: Integer -> String
getPath id = ".stack-work/" ++ show id ++ ".json"
publishEntity :: (Entity a) => a -> IO ()
publishEntity = print
main = do
let user1 = User 1 "Thomas" "Meier" "tm#meier.com"
storeEntity user1
user2 <- retrieveEntity 1 :: IO User
print user2
You can tie the types of storeEntity and retrieveEntity together by adding a type-level tag to your entity's identifier Integer. I think your API design also has a small infelicity that isn't critical, but I'll fix it along the way anyway. Namely: Users shouldn't store their identifier. Instead have a single top-level type wrapper for identified things. This lets you write code once and for all that munges identifiers -- e.g. a function that takes an entity that doesn't yet have an ID (how would you even represent this with your definition of User?) and allocates a fresh ID for it -- without going back and modifying your Entity class and all its implementations. Also storing first and last names separately is wrong. So:
import Data.Tagged
data User = User
{ name :: String
, email :: String
} deriving (Eq, Ord, Read, Show)
type Identifier a = Tagged a Integer
data Identified a = Identified
{ ident :: Identifier a
, val :: a
} deriving (Eq, Ord, Read, Show)
Here my Identified User corresponds to your User, and my User doesn't have an analog in your version. The Entity class might look like this:
class Entity a where
store :: Identified a -> IO ()
retrieve :: Identifier a -> IO a
publish :: a -> IO () -- or maybe Identified a -> IO ()?
instance Entity User -- stub
As an example of the "write it once and for all" principle above, you may find it convenient for retrieve to actually associate the entity it returns with its identifier. This can be done uniformly for all entities now:
retrieveIDd :: Entity a => Identifier a -> IO (Identified a)
retrieveIDd id = Identified id <$> retrieve id
Now we can write an action that ties together the types of its store and retrieve actions:
storeRetrievePublish :: Entity a => Identified a -> IO ()
storeRetrievePublish e = do
store e
e' <- retrieve (ident e)
publish e'
Here ident e has rich enough type information that we know that e' must be an a, even though we don't have an explicit type signature for it. (The signature on storeRetrievePublish is also optional; the one given here is the one inferred by GHC.) Finishing touches:
main :: IO ()
main = storeRetrievePublish (Identified 1 (User "Thomas Meier" "tm#meier.com"))
If you don't want to define storeRetrievePublish explicitly, you can get away with this:
main :: IO ()
main = do
let user = Identified 1 (User "Thomas Meier" "tm#meier.com")
store user
user' <- retrieve (ident user)
publish user'
...but you can't unfold definitions much further: if you reduce ident user to just 1, you will have lost the tie between the type tag on the identifier used for store and for retrieve, and be back to your ambiguous type situation.

Ambiguous occurrence compilation error of custom data types in Haskell

I have a custom data type Person and Employee (DataTypesAPI.hs)
{-# LANGUAGE DuplicateRecordFields #-}
data Person = Person {fName :: String
, lName :: String
} deriving (Show, Generic, FromJSON, ToJSON, ToBSON, FromBSON)
data Employee = Employee {fName :: String
, lName :: String
, id :: String
} deriving (Show, Generic, FromJSON, ToJSON, ToBSON, FromBSON)
I have an instance of Employee (as e) and want to create Person instance from it so that fName and lName will be populated from Employee. Code snippet is (src/MyLib.hs)
import DataTypesAPI.hs (Employee(..), Person(..))
DataLink.map (\e -> Person (fName e) (lName e))
However, as both types have same attributes name ghc give compilation error
Ambiguous occurrence ‘last_commit_hash’
It could refer to either the field ‘fName’,
imported from ‘FirstHaskellAPI’ at src/MyLib.hs:68:101-115
or the field ‘fName’,
imported from ‘FirstHaskellAPI’ at src/MyLib.hs:68:53-98
In later part of my code I need both types. How to resolve such compilation error?
Try disambiguating it using e.g.
DataLink.map (\e -> Person (fName e) (lName (e :: Employee)))

Why are type-safe relational operations so difficult?

I was trying to code a relational problem in Haskell, when I had to find out that doing this in a type safe manner is far from obvious. E.g. a humble
select 1,a,b, from T
already raises a number of questions:
what is the type of this function?
what is the type of the projection 1,a,b ? What is the type of a projection in general?
what is the result type and how do I express the relationship between the result type and the projection?
what is the type of such a function which accepts any valid projection?
how can I detect invalid projections at compile time ?
How would I add a column to a table or to a projection?
I believe even Oracle's PL/SQL language does not get this quite right. While invald projections are mostly detected at compile time, the is a large number of type errors which only show at runtime. Most other bindings to RDBMSs (e.g. Java's jdbc and perl's DBI) use SQL contained in Strings and thus give up type-safety entirely.
Further research showed that there are some Haskell libraries (HList, vinyl and TRex), which provide type-safe extensible records and some more. But these libraries all require Haskell extensions like DataKinds, FlexibleContexts and many more. Furthermore these libraries are not easy to use and have a smell of trickery, at least to uninitialized observers like me.
This suggests, that type-safe relational operations do not fit in well with the functional paradigm, at least not as it is implemented in Haskell.
My questions are the following:
What are the fundamental causes of this difficulty to model relational operations in a type safe way. Where does Hindley-Milner fall short? Or does the problem originate at typed lambda calculus already?
Is there a paradigm, where relational operations are first class citizens? And if so, is there a real-world implementation?
Let's define a table indexed on some columns as a type with two type parameters:
data IndexedTable k v = ???
groupBy :: (v -> k) -> IndexedTable k v
-- A table without an index just has an empty key
type Table = IndexedTable ()
k will be a (possibly nested) tuple of all columns that the table is indexed on. v will be a (possibly nested) tuple of all columns that the table is not indexed on.
So, for example, if we had the following table
| Id | First Name | Last Name |
|----|------------|-----------|
| 0 | Gabriel | Gonzalez |
| 1 | Oscar | Boykin |
| 2 | Edgar | Codd |
... and it were indexed on the first column, then the type would be:
type Id = Int
type FirstName = String
type LastName = String
IndexedTable Int (FirstName, LastName)
However, if it were indexed on the first and second column, then the type would be:
IndexedTable (Int, Firstname) LastName
Table would implement the Functor, Applicative, and Alternative type classes. In other words:
instance Functor (IndexedTable k)
instance Applicative (IndexedTable k)
instance Alternative (IndexedTable k)
So joins would be implemented as:
join :: IndexedTable k v1 -> IndexedTable k v2 -> IndexedTable k (v1, v2)
join t1 t2 = liftA2 (,) t1 t2
leftJoin :: IndexedTable k v1 -> IndexedTable k v2 -> IndexedTable k (v1, Maybe v2)
leftJoin t1 t2 = liftA2 (,) t1 (optional t2)
rightJoin :: IndexedTable k v1 -> IndexedTable k v2 -> IndexedTable k (Maybe v1, v2)
rightJoin t1 t2 = liftA2 (,) (optional t1) t2
Then you would have a separate type that we will call a Select. This type will also have two type parameters:
data Select v r = ???
A Select would consume a bunch of rows of type v from the table and produce a result of type r. In other words, we should have a function of type:
selectIndexed :: Indexed k v -> Select v r -> r
Some example Selects that we might define would be:
count :: Select v Integer
sum :: Num a => Select a a
product :: Num a => Select a a
max :: Ord a => Select a a
This Select type would implement the Applicative interface, so we could combine multiple Selects into a single Select. For example:
liftA2 (,) count sum :: Select Integer (Integer, Integer)
That would be analogous to this SQL:
SELECT COUNT(*), SUM(*)
However, often our table will have multiple columns, so we need a way to focus a Select onto a single column. Let's call this function Focus:
focus :: Lens' a b -> Select b r -> Select a r
So that we can write things like:
liftA3 (,,) (focus _1 sum) (focus _2 product) (focus _3 max)
:: (Num a, Num b, Ord c)
=> Select (a, b, c) (a, b, c)
So if we wanted to write something like:
SELECT COUNT(*), MAX(firstName) FROM t
That would be equivalent to this Haskell code:
firstName :: Lens' Row String
table :: Table Row
select table (liftA2 (,) count (focus firstName max)) :: (Integer, String)
So you might wonder how one might implement Select and Table.
I describe how to implement Table in this post:
http://www.haskellforall.com/2014/12/a-very-general-api-for-relational-joins.html
... and you can implement Select as just:
type Select = Control.Foldl.Fold
type focus = Control.Foldl.pretraverse
-- Assuming you define a `Foldable` instance for `IndexedTable`
select t s = Control.Foldl.fold s t
Also, keep in mind that these are not the only ways to implement Table and Select. They are just a simple implementation to get you started and you can generalize them as necessary.
What about selecting columns from a table? Well, you can define:
column :: Select a (Table a)
column = Control.Foldl.list
So if you wanted to do:
SELECT col FROM t
... you would write:
field :: Lens' Row Field
table :: Table Row
select (focus field column) table :: [Field]
The important takeaway is that you can implement a relational API in Haskell just fine without any fancy type system extensions.

Convert Lens' a b into Lens' a (Maybe b)

I have several data structures like
data Data1 = Data1
{ _data1Field :: Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data1
data Data2 = Data2
{ _data2Field :: Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data2
-- More similar data types
So I decided to write a simple type class to make it easier to compose
class HasField a where
field :: Lens' a Int
instance HasField Data1 where
field = data1Field
instance HasField Data2 where
field = data2Field
But then I ran into the problem that some of these structures have the corresponding field as optional
data Data3 = Data3
{ _data3Field :: Maybe Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data3
And now I can no longer use the type class. Since there are about the same number of data types that have that field optional as not, I decided that it'd be better to change the typeclass:
class HasField a where
field :: Lens' a (Maybe Int)
instance HasField Data3 where
field = data3Field
But since I'm not very experienced with the lens library, I'm stuck figuring out how to make this new lens work with the types for Data1 and Data2. Ideally, I'd like to be able to view it and get a Maybe Int value for any type, and when setting I'd like Just x to set the field to x for Data1 and Data2 and be a no-op for those two types when passed Nothing.
Is this possible using existing combinators or am I going to have to write the lens myself? I'm fine doing so, but the majority of existing tutorials use TH and gloss over the details of writing one by hand.
I'm using GHC 7.6.3 and lens 3.10.
As a follow up to shachaf
class HasFieldA d where
field :: Traversal' d Int
instance HasFieldA Data1 where
field = data1Field -- Lens's are Traversals
instance HasFieldA Data3 where
field = data3Field . _Just
And then the ^? operator or the ^.. operator
getField :: HasFieldA d => d -> Maybe Int
getField = d ^? field -- or preview field d
to get it.
To set optional fields, you'd need another function
class SetFieldA d where
setField :: Setter' d Int
instance SetFieldA Data3 where
setField = set data3Field . Just

Confused about custom data types in Haskell

The task: I am trying to create a custom data type and have it able to print to the console. I also want to be able to sort it using Haskell's natural ordering.
The issue: Write now, I can't get this code to compile. It throws the following error: No instance for (Show Person) arising from a use of 'print'.
What I have so far:
-- Omitted working selection-sort function
selection_sort_ord :: (Ord a) => [a] -> [a]
selection_sort_ord xs = selection_sort (<) xs
data Person = Person {
first_name :: String,
last_name :: String,
age :: Int }
main :: IO ()
main = print $ print_person (Person "Paul" "Bouchon" 21)
You need a Show instance to convert the type to a printable representation (a String). The easiest way to obtain one is to add
deriving Show
to the type definition.
data Person = Person {
first_name :: String,
last_name :: String,
age :: Int }
deriving (Eq, Ord, Show)
to get the most often needed instances.
If you want a different Ord instance, as suggested in the comments, instead of deriving that (keep deriving Eq and Show unless you want different behaviour for those), provide an instance like
instance Ord Person where
compare p1 p2 = case compare (age p1) (age p2) of
EQ -> case compare (last_name p1) (last_name p2) of
EQ -> compare (first_name p1) (first_name p2)
other -> other
unequal -> unequal
or use pattern matching in the definition of compare if you prefer,
compare (Person first1 last1 age1) (Person first2 last2 age2) =
case compare age1 age2 of
EQ -> case compare last1 last2 of
EQ -> compare first1 first2
other -> other
unequal -> unequal
That compares according to age first, then last name, and finally, if needed, first name.

Resources