SQLite3 Row <-> Data models -- Is this a typical Haskell pattern ?

Hey Everyone, Greetings, I am a total newb to haskell, so, I have a strange question (perhaps). Consider I have a data model which looks like this; data Brand = Brand { id :: Int, name :: String, created_at :: String, updated_at :: String } Now, I have a sqlite3 function such as checkout :: Int -> IO (Either String [[Row Value]]) checkout a = do handle <- openConnection "/Users/stef/haskell/db/development.sqlite3" execStatement handle $ "SELECT * from brands where id = " ++ show a From this, I get a Row/Tuple. So far, so good, but, the question _I_ have is, how do you go about mapping a returned row to the data model ? Is this even a design pattern that is used in FP languages ? I admit, I have spent numerous years in the MVC world, so, perhaps this is simply "not done". It would seem to be a much nicer thing to then do ; name myBrandModel Thanks for reading this far, feel free to complain about my design :D Regards S.

On Sat, Mar 19, 2011 at 7:21 PM, Stef T
Hey Everyone, Greetings, I am a total newb to haskell, so, I have a strange question (perhaps). Consider I have a data model which looks like this;
data Brand = Brand { id :: Int, name :: String, created_at :: String, updated_at :: String }
Now, I have a sqlite3 function such as
checkout :: Int -> IO (Either String [[Row Value]]) checkout a = do handle <- openConnection "/Users/stef/haskell/db/development.sqlite3" execStatement handle $ "SELECT * from brands where id = " ++ show a
From this, I get a Row/Tuple. So far, so good, but, the question _I_ have is, how do you go about mapping a returned row to the data model ? Is this even a design pattern that is used in FP languages ? I admit, I have spent numerous years in the MVC world, so, perhaps this is simply "not done". It would seem to be a much nicer thing to then do ;
What problem are you running into trying to do this? You would need to write functions to convert each column into the format you want it for the Brand type, and then pass output of the functions Brand data constructor. Depending on the format of the data and the library you're using these functions might turn out to be pretty simple. It's considered good in Haskell to get data out of "weak" types into specific types when you want them, as in from a String or from a 'Row Value' - it makes manipulations of the values easier to read and you get the compiler's help figuring things out. Which SQL library are you using?
name myBrandModel
Thanks for reading this far, feel free to complain about my design :D Regards S. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Mar 19, 2011, at 5:43 PM, Antoine Latter wrote:
On Sat, Mar 19, 2011 at 7:21 PM, Stef T
wrote: Hey Everyone, Greetings, I am a total newb to haskell, so, I have a strange question (perhaps). Consider I have a data model which looks like this;
data Brand = Brand { id :: Int, name :: String, created_at :: String, updated_at :: String }
Now, I have a sqlite3 function such as
checkout :: Int -> IO (Either String [[Row Value]]) checkout a = do handle <- openConnection "/Users/stef/haskell/db/development.sqlite3" execStatement handle $ "SELECT * from brands where id = " ++ show a
From this, I get a Row/Tuple. So far, so good, but, the question _I_ have is, how do you go about mapping a returned row to the data model ? Is this even a design pattern that is used in FP languages ? I admit, I have spent numerous years in the MVC world, so, perhaps this is simply "not done". It would seem to be a much nicer thing to then do ;
What problem are you running into trying to do this?
You would need to write functions to convert each column into the format you want it for the Brand type, and then pass output of the functions Brand data constructor. Depending on the format of the data and the library you're using these functions might turn out to be pretty simple.
I guess I am having a fundamental disconnect in 'how' to do it nicely (or DRY-ly). the format of the row is ; Right [[[("id",Int 4239),("name",Text "Zoppini"),("created_at",Text "2011-02-02 20:51:44.706633+0000"),("updated_at",Text "2011-02-02 20:51:44.706633+0000")]]] I had attempted to do something along the lines of ; getBrand :: Int -> Brand getBrand a = do b <- checkout a Brand { id = b id, name = b name } but, that explodes (not least of which is the id being a reserved keyword from prelude)
It's considered good in Haskell to get data out of "weak" types into specific types when you want them, as in from a String or from a 'Row Value' - it makes manipulations of the values easier to read and you get the compiler's help figuring things out.
makes sense. It also helps -me- (and possibly future programmers/maintainers) to understand what the heck is going on.
Which SQL library are you using?
I am using the haskell sqlite (version 0.5.2) Regards S.
name myBrandModel
Thanks for reading this far, feel free to complain about my design :D Regards S. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

On Sat, Mar 19, 2011 at 8:14 PM, Stef T
On Mar 19, 2011, at 5:43 PM, Antoine Latter wrote:
On Sat, Mar 19, 2011 at 7:21 PM, Stef T
wrote: Hey Everyone, Greetings, I am a total newb to haskell, so, I have a strange question (perhaps). Consider I have a data model which looks like this;
data Brand = Brand { id :: Int, name :: String, created_at :: String, updated_at :: String }
Now, I have a sqlite3 function such as
checkout :: Int -> IO (Either String [[Row Value]]) checkout a = do handle <- openConnection "/Users/stef/haskell/db/development.sqlite3" execStatement handle $ "SELECT * from brands where id = " ++ show a
From this, I get a Row/Tuple. So far, so good, but, the question _I_ have is, how do you go about mapping a returned row to the data model ? Is this even a design pattern that is used in FP languages ? I admit, I have spent numerous years in the MVC world, so, perhaps this is simply "not done". It would seem to be a much nicer thing to then do ;
What problem are you running into trying to do this?
You would need to write functions to convert each column into the format you want it for the Brand type, and then pass output of the functions Brand data constructor. Depending on the format of the data and the library you're using these functions might turn out to be pretty simple.
I guess I am having a fundamental disconnect in 'how' to do it nicely (or DRY-ly).
the format of the row is ;
Right [[[("id",Int 4239),("name",Text "Zoppini"),("created_at",Text "2011-02-02 20:51:44.706633+0000"),("updated_at",Text "2011-02-02 20:51:44.706633+0000")]]]
I had attempted to do something along the lines of ;
getBrand :: Int -> Brand getBrand a = do b <- checkout a Brand { id = b id, name = b name }
but, that explodes (not least of which is the id being a reserved keyword from prelude)
First - 'id' is reserved, it's an ordinary function. But it can be confusing to give things the same name as things in the Prelude. Here you're running into a few problems - is there a tutorial you're working with? There are some good ones over here: http://www.haskell.org/haskellwiki/Tutorials First is the type of your function:
getBrand :: Int -> Brand
Since you're calling functions which do IO (to get data from the database) in your function, your function needs to note that in its type signature:
getBrand :: Int -> IO Brand
On to the body of the function:
getBrand a = do b <- checkout a Brand { id = b id, name = b name }
In the second line of the body, you have "b id" and "b name", this is treating "b" has if it were a function, and calling it first with the value "id" and then with the value "name" which is almost certainly not what you want. I don't know much about the library you're using, but you can start with the types of the functions to figure out what to do with them. Here, the value 'b' os of type "Either String [[Row Value]]", so you can use a case statement to deconstruct the out-side 'Either' type:
case b of Left errorStr -> [do something with the error message] Right rows -> [do something with the list of rows]
In this bit of code, the value 'rows' is of type '[[Row Value]]', so then you have to make choices about what to do if the list is empty, or if the list has more than row. Once you have a row you then need to lookup its type and figure out how to take it apart and make sense of the values. So you've got more code to write :-) I don't have much experience mixing SQL and Haskell, so there might be tools to automate some of this. Antoine
It's considered good in Haskell to get data out of "weak" types into specific types when you want them, as in from a String or from a 'Row Value' - it makes manipulations of the values easier to read and you get the compiler's help figuring things out.
makes sense. It also helps -me- (and possibly future programmers/maintainers) to understand what the heck is going on.
Which SQL library are you using?
I am using the haskell sqlite (version 0.5.2)
Regards S.
name myBrandModel
Thanks for reading this far, feel free to complain about my design :D Regards S. _______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners
participants (2)
-
Antoine Latter
-
Stef T