packages feed

selda 0.1.1.0 → 0.1.1.1

raw patch · 4 files changed

+123/−14 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Database.Selda.Generic: [:-] :: (a -> b) -> Attribute -> GenAttr a
+ Database.Selda.Generic: data GenAttr a
- Database.Selda.Generic: genTable :: forall a b. Relational a => TableName -> [(a -> b, Attribute)] -> GenTable a
+ Database.Selda.Generic: genTable :: forall a. Relational a => TableName -> [GenAttr a] -> GenTable a

Files

ChangeLog.md view
@@ -1,5 +1,13 @@ # Revision history for selda -## 0.1.0.0  -- 2017-04-14+## 0.1.1.1 -- 2017-04-20++* Generic tables, queries and mutation.+* Select from inline tables.+* Tutorial updates.+* Minor bugfixes.+++## 0.1.0.0 -- 2017-04-14  * Initial release.
README.md view
@@ -22,15 +22,30 @@   add-on packages.  +Getting started+===============++Install the `selda` package from Hackage, as well as at least one of the+backends:++    $ cabal update+    $ cabal install selda selda-sqlite selda-postgresql++Then, read the [tutorial](#tutorial).+The [API documentation](http://hackage.haskell.org/package/selda) will probably+also come in handy.++ Requirements ============ -Selda requires SQLite 3.7.11+, or PostgreSQL 9+.+Selda requires GHC 7.10+, as well as SQLite 3.7.11+ or PostgreSQL 9+. To build the SQLite backend, you need a C compiler installed. To build the PostgreSQL backend, you need the `libpq` development libraries installed (`libpq-dev` on Debian-based Linux distributions).  +<span id="tutorial"></span> A brief tutorial ================ @@ -422,7 +437,7 @@ enjoys. Using transactions in Selda is super easy:  ```-transferMoney :: Text -> Text -> Double -> SeldaT s ()+transferMoney :: Text -> Text -> Double -> SeldaT IO () transferMoney from to amount = do   transaction $ do     update_ accounts (\(owner :*: _) -> owner .== text from)@@ -483,6 +498,88 @@ application modifying the same database as long as they're all using Selda to do it, as the cache shared between all Selda computations running in the same process.+++Generic tables and queries+==========================++Selda also supports building tables and queries from (almost) arbytrary+data types, using the `Database.Selda.Generic` module.+Re-implementing the ad hoc `people` and `addresses` tables from before in a+more disciplined manner in this way is quite easy:++```+data Person = Person+  { personName :: Text+  , age        :: Int+  , pet        :: Maybe Int+  } deriving Generic++data Address = Address+  { addrName :: Text+  , city     :: Text+  } deriving Generic+++people :: GenTable Person+people = genTable "people" [personName :- primaryGen]++addresses :: GenTable Address+addresses = genTable "addresses" [personName :- primaryGen]+```++This will declare two tables with the same structure as their ad hoc+predecessors. Creating the tables is similarly easy:++```+create :: SeldaT IO ()+create = do+  createTable (gen people)+  createTable (gen addresses)+```++Note the use of the `gen` function here, to extract the underlying table of+columns from the generic table.++With generic tables, you can use the table's datatype's record selectors+together with the `!` operator to access its columns in queries.++```+genericGrownups :: Query s (Col s Text)+genericGrownups = do+  person <- select (gen people)+  restrict (person ! age .> 20)+  return (person ! personName)+```++However, queries over generic tables aren't magic; they still consist of the+same collections of columns as queries over non-generic tables.++```+genericGrownups2 :: Query s (Col s Text)+genericGrownups2 = do+  (name :*: age :*: _) <- select (gen people)+  restrict (age .> 20)+  return name+```++Finally, with generics it's also quite easy to re-assemble Haskell objects+from the results of a query using the `fromRel` function.++```+getPeopleOfAge :: Int -> SeldaT IO [Person]+getPeopleOfAge yrs = do+  ps <- query $ do+    p <- select (gen people)+    restrict (p ! age .== yrs)+    return p+  return (map fromRel ps)+```++And with that, we conclude this tutorial. Hopefully it has been enough to get+you comfortable started using Selda.+For a more detailed API reference, please see Selda's+[Haddock documentation](http://hackage.haskell.org/package/selda).   TODOs
selda.cabal view
@@ -1,5 +1,5 @@ name:                selda-version:             0.1.1.0+version:             0.1.1.1 synopsis:            Type-safe, high-level EDSL for interacting with relational databases. description:         This package provides an EDSL for writing portable, type-safe, high-level                      database code. Its feature set includes querying and modifying databases,
src/Database/Selda/Generic.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE TypeFamilies, TypeOperators, FlexibleInstances #-} {-# LANGUAGE UndecidableInstances, MultiParamTypeClasses, OverloadedStrings #-} {-# LANGUAGE FlexibleContexts, ScopedTypeVariables, ConstraintKinds #-}+{-# LANGUAGE GADTs #-} -- | Build tables and database operations from (almost) any Haskell type. -- --   While the types in this module may look somewhat intimidating, the rules@@ -14,13 +15,13 @@ --     * Performing a 'select' on a generic table returns all the table's fields --       as an inductive tuple. --     * Tuples obtained this way can be handled either as any other tuple, or---       using the '(!)' operator together with any record selector for the+--       using the '!' operator together with any record selector for the --       tuple's corresponding type. --     * Relations obtained from a query can be re-assembled into their --       corresponding data type using 'fromRel'. module Database.Selda.Generic   ( Relational, Generic-  , GenTable (..), Attribute, Relation+  , GenAttr (..), GenTable (..), Attribute, Relation   , genTable, toRel, fromRel, (!)   , insertGen, insertGen_, insertGenWithPK   , primaryGen, autoPrimaryGen@@ -68,6 +69,12 @@ --   of @Foo@ has type @Int@, and the second has type @Text@. type Relation a = Rel (Rep a) +-- | A generic column attribute.+--   Essentially a pair or a record selector over the type @a@ and a column+--   attribute.+data GenAttr a where+  (:-) :: (a -> b) -> Attribute -> GenAttr a+ -- | Generate a table from the given table name and list of column attributes. --   All @Maybe@ fields in the table's type will be represented by nullable --   columns, and all non-@Maybe@ fields fill be represented by required@@ -88,9 +95,9 @@ --   This example will create a table with the column types --   @Int :*: Text :*: Int :*: Maybe Text@, where the first field is --   an auto-incrementing primary key.-genTable :: forall a b. Relational a+genTable :: forall a. Relational a          => TableName-         -> [(a -> b, Attribute)]+         -> [GenAttr a]          -> GenTable a genTable tn attrs = GenTable $ Table tn (validate tn (map tidy cols))   where@@ -99,7 +106,7 @@     addAttrs n ci = ci       { colAttrs = colAttrs ci ++ concat           [ as-          | (f, Attribute as) <- attrs+          | f :- Attribute as <- attrs           , identify dummy f == n           ]       }@@ -109,7 +116,7 @@ --   of all of the type's fields. -- -- > data Person = Person--- >   { id   :: Auto Int+-- >   { id   :: Int -- >   , name :: Text -- >   , age  :: Int -- >   , pet  :: Maybe Text@@ -121,9 +128,6 @@ -- --   This is mainly useful when inserting values into a table using 'insert' --   and the other functions from "Database.Selda".---   Note that since @toRel@ doesn't filter out auto-incrementing primary key---   fields, you should use 'insertGen' and friends to insert values into---   tables with auto-incrementing primary keys instead. toRel :: Relational a => a -> Relation a toRel = gToRel . from @@ -173,7 +177,7 @@ --   selector function. For instance: -- -- > data Person = Person--- >   { id   :: Auto Int+-- >   { id   :: Int -- >   , name :: Text -- >   , age  :: Int -- >   , pet  :: Maybe Text