ribbit 0.3.0.1 → 0.4.0.0
raw patch · 3 files changed
+121/−38 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Database.Ribbit: data X l r
- Database.Ribbit: instance forall k1 k2 (l :: k2) (r :: k1) (lname :: GHC.Types.Symbol) (rname :: GHC.Types.Symbol). (Database.Ribbit.Table l, Database.Ribbit.Table r, GHC.TypeLits.KnownSymbol lname, GHC.TypeLits.KnownSymbol rname) => Database.Ribbit.Table (Database.Ribbit.X (Database.Ribbit.As l lname) (Database.Ribbit.As r rname))
+ Database.Ribbit: data DeleteFrom table
+ Database.Ribbit: instance forall k (table :: k) (name :: GHC.Types.Symbol) (moreTables :: [*]). (Database.Ribbit.Table table, GHC.TypeLits.KnownSymbol name) => Database.Ribbit.Table (Database.Ribbit.As table name : moreTables)
+ Database.Ribbit: instance forall k (table :: k). GHC.TypeLits.KnownSymbol (Database.Ribbit.Name table) => Database.Ribbit.Render (Database.Ribbit.DeleteFrom table)
Files
- README.md +26/−11
- ribbit.cabal +1/−1
- src/Database/Ribbit.hs +94/−26
README.md view
@@ -8,8 +8,8 @@ - [Conditionals](#conditionals) - [Limited `CREATE TABLE` support.](#limited-create-table-support) - [`INSERT INTO` support.](#insert-into-support)+ - [`DELETE FROM` support.](#delete-from-support) - [Roadmap](#roadmap)- - [DELETE support](#delete-support) - [UPDATE support](#update-support) - [Flesh out Haskell to PostgreSQL type mapping.](#flesh-out-haskell-to-postgresql-type-mapping) - [How it compares with other libraries.](#how-it-compares-with-other-libraries)@@ -69,7 +69,7 @@ We support queries of the form: ```haskell-type MyQuery = Select '["t1.field1", "t2.field2"] `From` MyTable1 `As` "t1" `X` MyTable2 `As` "t2"+type MyQuery = Select '["t1.field1", "t2.field2"] `From` '[MyTable1 `As` "t1", MyTable2 `As` "t2"] ``` #### Conditionals@@ -129,14 +129,29 @@ (Only 1 :> Only "Bob Marley" :> Only 36) ``` -## Roadmap+#### `DELETE FROM` support. -This is what I plan to work on next:+Basic deletes are supported: -### DELETE support+```haskell+type MyDeleteEveryone = DeleteFrom PeopleTable+type MyDeleteById = DeleteFrom PeopleTable `Where` id `Equals` (?) -Support delete operations.+execute+ conn+ (Proxy :: Proxy MyDeleteEveryone)+ () +execute+ conn+ (Proxy :: Proxy MyDeleteById)+ (Only 1)+```++## Roadmap++This is what I plan to work on next:+ ### UPDATE support Support update operations.@@ -181,11 +196,11 @@ Then you would be free to deconstruct this type (using type families), transform it into another schema, generate customized `CREATE TABLE`- statements if the (forthcoming) ones provided aren't good enough for your- back-end or use case... that sort of thing. As a somewhat contrived example:- maybe, for who knows what reason, you never want to allow null values in your- database. You can write a type family that can inspect every field in an- arbitrary schema, replacing all the `Maybe a` with just `a`, like:+ statements if the ones provided aren't good enough for your back-end or+ use case... that sort of thing. As a somewhat contrived example: maybe,+ for who knows what reason, you never want to allow null values in your+ database. You can write a type family that can inspect every field in+ an arbitrary schema, replacing all the `Maybe a` with just `a`, like: ```haskell -- With -XPolyKinds
ribbit.cabal view
@@ -1,6 +1,6 @@ name: ribbit-version: 0.3.0.1+version: 0.4.0.0 synopsis: Type-level Relational DB combinators. description: Ribbit is yet another type safe relational database library for Haskell, heavily inspired by the
src/Database/Ribbit.hs view
@@ -47,6 +47,9 @@ -- ** Inserting values -- $insert + -- ** Deleting values+ -- $delete+ -- * Schema Definition Types (:>)(..), Table(..),@@ -55,12 +58,14 @@ -- * Query Combinators Select, From,- X, As, Where, -- * Insert Combinators InsertInto,+ + -- * Delete Combinators+ DeleteFrom, -- ** Condition Conbinators And,@@ -160,7 +165,10 @@ -- > type MyQuery = -- > Select '["e.name", "e.salary"] -- > `From`--- > Company `As` "c" `X` Employee `As` "e"+-- > '[+-- > Company `As` "c",+-- > Employee `As` "e"+-- > ] -- > `Where` -- > "c.id" `Equals` "e.company_id" -- > `And` "c.name" `Equals` (?)@@ -259,7 +267,35 @@ -- > (Proxy :: Proxy InsertEmployee) -- > (Only 1 :> Only 1 :> Only "Rick" :> Only myBirthday) +-- $delete+-- Deleting a value is similar to inserting a value, but simpler because+-- you only have to specify the delete conditions (if there are any).+-- +-- e.g.:+-- +-- > type DeleteAllEmployees = DeleteFrom Employee+-- > type DeleteEmployeeById =+-- > DeleteFrom Employee+-- > `Where` "id" `Equals` (?)+-- +-- Then just execute the query, providing the appropriate query params.+-- +-- > do+-- > let+-- > employeeId :: Int+-- > employeeId = ...+-- > execute+-- > conn+-- > (Proxy :: Proxy DeleteEmployeeById)+-- > (Only employeeId)+-- >+-- > -- Or maybe delete all employees.+-- > execute+-- > conn+-- > (Proxy :: Proxy DeleteAllEmployees)+-- > () + {- | "SELECT" combinator, used for starting a @SELECT@ statement. -} data Select fields @@ -317,11 +353,6 @@ infixr 7 `Or` -{- | Cross product operator for FROM clauses. -}-data X l r-infixr 7 `X`-- {- | "AS" combinator, used for attaching a name to a table in a FROM clause. -} data As relation name infix 8 `As`@@ -399,7 +430,6 @@ LookupType name a context = NotInSchema name context - {- | Type class for defining your own tables. The primary way for you to introduce a new schema is to instantiate this type class for one of@@ -421,20 +451,42 @@ type DBSchema relation {- | Cross product -}-instance (Table l, Table r, KnownSymbol lname, KnownSymbol rname) => Table (l `As` lname `X` r `As` rname) where- type DBSchema (l `As` lname `X` r `As` rname) =+instance+ (Table table, KnownSymbol name)+ =>+ Table ((table `As` name) : moreTables)+ where+ type DBSchema ((table `As` name) : moreTables) =+ CrossProductSchema ((table `As` name) : moreTables)+ type Name ((table `As` name) : moreTables) =+ CrossProductName ((table `As` name) : moreTables)+++{- | Produce the schema of a cross product. -}+type family CrossProductSchema cp where+ CrossProductSchema '[table `as` name] = Flatten (- AliasAs lname (DBSchema l)- :> AliasAs rname (DBSchema r)+ AliasAs name (DBSchema table) )- type Name (l `As` lname `X` r `As` rname) =- Name l+ CrossProductSchema ((table `As` name) : moreTables) =+ Flatten (+ AliasAs name (DBSchema table)+ :> CrossProductSchema moreTables+ )+++{- | Product the renderable "name" of a cross product. -}+type family CrossProductName cp where+ CrossProductName '[table `As` name] = + Name table `AppendSymbol` " as "- `AppendSymbol` lname- `AppendSymbol` ", "- `AppendSymbol` Name r+ `AppendSymbol` name+ CrossProductName ((table `As` name) : moreTables) = + Name table `AppendSymbol` " as "- `AppendSymbol` rname+ `AppendSymbol` name+ `AppendSymbol` ", "+ `AppendSymbol` CrossProductName moreTables {- |@@ -469,6 +521,8 @@ type family ArgsType query where ArgsType (_ `From` relation `Where` conditions) = ArgsType (DBSchema relation, conditions)+ ArgsType (DeleteFrom relation `Where` conditions) =+ ArgsType (DBSchema relation, conditions) ArgsType (InsertInto relation '[]) = TypeError ('Lit.Text "Insert statement must specify at least one column.") ArgsType (InsertInto relation fields) =@@ -654,15 +708,25 @@ render _proxy = "?" {- INSERT -}-instance (ReflectFields fields, KnownSymbol (Name table)) => Render (InsertInto table fields) where+instance+ (ReflectFields fields, KnownSymbol (Name table))+ =>+ Render (InsertInto table fields)+ where+ render _proxy =+ let+ fields :: [Text]+ fields = reflectFields (Proxy @fields)+ in+ "insert into " <> symbolVal (Proxy @(Name table))+ <> " (" <> T.intercalate ", " fields <> ")"+ <> " values (" <> T.intercalate ", " (const "?" <$> fields) <> ");"+++{- DELETE -}+instance (KnownSymbol (Name table)) => Render (DeleteFrom table) where render _proxy =- let- fields :: [Text]- fields = reflectFields (Proxy @fields)- in- "insert into " <> symbolVal (Proxy @(Name table))- <> " (" <> T.intercalate ", " fields <> ")"- <> " values (" <> T.intercalate ", " (const "?" <$> fields) <> ");"+ "delete from " <> symbolVal (Proxy @(Name table)) {- | Insert statement. -}@@ -676,5 +740,9 @@ reflectFields _proxy = [] instance (KnownSymbol a, ReflectFields more) => ReflectFields (a:more) where reflectFields _proxy = symbolVal (Proxy @a) : reflectFields (Proxy @more)+++{- | Delete statement. -}+data DeleteFrom table