I've been looking into the Persistent library to interface with sql databases. Suppose I have a database containing recipes, with Recipe, Ingredient, and RecIng tables.
My (admittedly limited) understanding of persistent leads me to believe I should define the tables like this:
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Recipe
title String
Ingredient
name String
RecIng
recId RecipeId
ingId IngredientId
quantity Int
|]
With this, it is possible to use Esqueleto to get the inner join between these tables:
select $
from $ \(i `InnerJoin ` ri `InnerJoin` r) -> do
on (r ^. RecipeId ==. ri ^. RecIngIngId)
on (i ^. IngredientId ==. ri ^. RegIngRecId)
return (r, ri, i)
This returns tuple of (Recipe, RecIng, Ingredient).
What I really want is a way to query recipes that results in the following:
data Recipe = Recipe { title :: String
, ingredients :: [Ingredient]
}
data Ingredient = Ingredient { name :: String
, quantity :: Integer
}
Other than defining an additional set of data types, and converting the tuples, is there a best practice for doing this kind of thing?
+1 to Adam's comment, it's the right answer IMO.
A separate approach you could take would be to use embedded entities, which would essentially mean JSON-encoding the list of ingredients into each recipe. But this would be bad SQL design, would cause table locking issues for updates, and wouldn't scale well for large numbers of ingredients.
In other words, there's a mismatch between the Haskell representation you want to work with and the right way to store the data in the database. This doesn't mean there's a problem with either your database format or your Haskell datatypes: it's a logical difference. The right response to this gap is to have two datatypes and an intelligent way to convert between them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With