-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/
-- | ribbit
--
-- ribbit
@package ribbit
@version 0.3.0.0
-- | This module attepts to define a type-level language for describing
-- database shcemas (i.e. schemas "as a type"), and the queries that
-- operate on them in such a way that:
--
-- 1) The schema and/or query is completely defined at the type level
-- (sans runtime arguments to query parameters).
--
-- 2) The meaning of a schema and/or query is immediately obvious to
-- anyone who knows SQL, and
--
-- 3) The schema and/or query can be extended, deconstructed, or
-- interpreted by third parties for their own purposes.
--
-- To that end, each schema is a new type, defined by you, using the
-- combinators provided by this library. The same goes for queries. Each
-- query is a separate type defined with combinators from this library.
--
-- We provide a PostgreSQL backend so that real work can be accomplished,
-- but if the backend is missing something you need, then the idea is
-- that you can use your own type families and type classes to extend the
-- schema and query languages, or interpret them differently for your own
-- needs including writing entirely new backends if need be.
module Database.Ribbit
-- | String two types together. Int :> Int
-- :> Int is similar in principal to the nested tuple
-- (Int, (Int, Int)), but looks a whole lot nicer
-- when the number of elements becomes large.
--
-- This is how you build up a schema from a collection of Field
-- types.
--
-- E.g.:
--
--
-- Field "foo" Int
-- :> Field "bar" Text
-- :> Field "baz" (Maybe Text)
--
--
-- It also the mechanism by which this library builds up the Haskell
-- types for query parameters and resulting rows that get returned. So if
-- you have a query that accepts three text query parameters, that type
-- represented in Haskell is going to be (Only Text
-- :> Only Text :> Only
-- Text).
--
-- If that query returns rows that contain a Text, an Int, and a Text,
-- then the type of the rows will be (Only Text
-- :> Only Int :> Only
-- Text).
data a :> b
(:>) :: a -> b -> (:>) a b
infixr 5 :>
infixr 5 :>
-- | 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
-- your types.
--
-- E.g.:
--
--
-- data MyTable
-- instance Table MyTable where
-- type Name MyTable = "my_table"
-- type DBSchema MyTable =
-- Field "id" Int
-- :> Field "my_non_nullable_text_field" Text
-- :> Field "my_nullable_int_field" (Maybe Int)
--
class Table relation where {
type family Name relation :: Symbol;
type family DBSchema relation;
}
-- | Define a field in a database schema, where:
--
--
-- - name: is the name of the database column, expressed as a
-- type-level string literal, and
-- - typ: is the Haskell type whose values get stored in the
-- column.
--
--
-- E.g:
--
--
data Field name typ
-- | SELECT combinator, used for starting a SELECT
-- statement.
data Select fields
-- | FROM combinator, used for attaching a SELECT projection to a
-- relation in the database.
data From proj relation
infixl 6 `From`
-- | 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`
-- | WHERE combinator, used for attaching conditions to a query.
data Where query conditions
infixl 6 `Where`
-- | Insert statement.
data InsertInto table fields
-- | AND combinator for conditions.
data And l r
infixr 8 `And`
-- | OR combinator for conditions.
data Or l r
infixr 7 `Or`
-- | "=" combinator for conditions.
data Equals l r
infix 9 `Equals`
-- | "!=" combinator for conditions.
data NotEquals l r
infix 9 `NotEquals`
-- | ">" combinator for conditions.
data Gt l r
infix 9 `Gt`
-- | ">=" combinator for conditions.
data Gte l r
infix 9 `Gte`
-- | "<" combinator for conditions.
data Lt l r
infix 9 `Lt`
-- | "<=" combinator for conditions.
data Lte l r
infix 9 `Lte`
-- | NOT conditional combinator.
data Not a
-- | "?" combinator, used to indicate the presence of a query parameter.
data (?)
-- | Produce the type represeting the placeholder ("?") values in a
-- paramaterized query.
type family ArgsType query
-- | Produce the type of rows return by a query.
type family ResultType query
-- | Type level check to see if the field is actually contained in the
-- schema
type family ValidField field schema
type family ProjectionType proj schema
-- | Render a type-level query as text.
class Render query
render :: Render query => proxy query -> Text
instance (GHC.Show.Show a, GHC.Show.Show b) => GHC.Show.Show (a Database.Ribbit.:> b)
instance (GHC.Classes.Ord a, GHC.Classes.Ord b) => GHC.Classes.Ord (a Database.Ribbit.:> b)
instance (GHC.Classes.Eq a, GHC.Classes.Eq b) => GHC.Classes.Eq (a Database.Ribbit.:> b)
instance (GHC.TypeLits.KnownSymbol field, Database.Ribbit.ReflectFields (field : more)) => Database.Ribbit.Render (field : more)
instance forall k1 k2 (fields :: k2) (table :: k1). (Database.Ribbit.ReflectFields fields, GHC.TypeLits.KnownSymbol (Database.Ribbit.Name table)) => Database.Ribbit.Render (Database.Ribbit.InsertInto table fields)
instance Database.Ribbit.ReflectFields '[]
instance (GHC.TypeLits.KnownSymbol a, Database.Ribbit.ReflectFields more) => Database.Ribbit.ReflectFields (a : more)
instance forall k (fields :: k). Database.Ribbit.Render fields => Database.Ribbit.Render (Database.Ribbit.Select fields)
instance forall k1 k2 (relation :: k2) (proj :: k1). (GHC.TypeLits.KnownSymbol (Database.Ribbit.Name relation), Database.Ribbit.Render proj, Database.Ribbit.Table relation) => Database.Ribbit.Render (Database.Ribbit.From proj relation)
instance forall k1 k2 (query :: k2) (conditions :: k1). (Database.Ribbit.Render query, Database.Ribbit.Render conditions) => Database.Ribbit.Render (Database.Ribbit.Where query conditions)
instance forall k1 k2 (l :: k2) (r :: k1). (Database.Ribbit.Render (Database.Ribbit.Expr l), Database.Ribbit.Render (Database.Ribbit.Expr r)) => Database.Ribbit.Render (Database.Ribbit.Equals l r)
instance forall k1 k2 (l :: k2) (r :: k1). (Database.Ribbit.Render (Database.Ribbit.Expr l), Database.Ribbit.Render (Database.Ribbit.Expr r)) => Database.Ribbit.Render (Database.Ribbit.NotEquals l r)
instance forall k (a :: k). Database.Ribbit.Render a => Database.Ribbit.Render (Database.Ribbit.Not a)
instance forall k1 k2 (l :: k2) (r :: k1). (Database.Ribbit.Render (Database.Ribbit.Expr l), Database.Ribbit.Render (Database.Ribbit.Expr r)) => Database.Ribbit.Render (Database.Ribbit.Gt l r)
instance forall k1 k2 (l :: k2) (r :: k1). (Database.Ribbit.Render (Database.Ribbit.Expr l), Database.Ribbit.Render (Database.Ribbit.Expr r)) => Database.Ribbit.Render (Database.Ribbit.Gte l r)
instance forall k1 k2 (l :: k2) (r :: k1). (Database.Ribbit.Render (Database.Ribbit.Expr l), Database.Ribbit.Render (Database.Ribbit.Expr r)) => Database.Ribbit.Render (Database.Ribbit.Lt l r)
instance forall k1 k2 (l :: k2) (r :: k1). (Database.Ribbit.Render (Database.Ribbit.Expr l), Database.Ribbit.Render (Database.Ribbit.Expr r)) => Database.Ribbit.Render (Database.Ribbit.Lte l r)
instance forall k1 k2 (l :: k2) (r :: k1). (Database.Ribbit.Render l, Database.Ribbit.Render r) => Database.Ribbit.Render (Database.Ribbit.And l r)
instance forall k1 k2 (l :: k2) (r :: k1). (Database.Ribbit.Render l, Database.Ribbit.Render r) => Database.Ribbit.Render (Database.Ribbit.Or l r)
instance Database.Ribbit.Render (Database.Ribbit.Expr (Database.Ribbit.?))
instance GHC.TypeLits.KnownSymbol a => Database.Ribbit.Render (Database.Ribbit.Expr a)
instance Database.Ribbit.Render (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))
-- | "postgresql-simple"-backed query ribbit implementation.
module Database.Ribbit.PostgreSQL
-- | Given a Haskell type, produce the PostgreSQL type of columns that
-- store values of that haskell type.
class HasPsqlType a
psqlType :: HasPsqlType a => proxy a -> PsqlType
-- | Represents the "base" PostgreSQL type. We say "base" type because
-- whether the type is nullable is handle automatically.
--
-- e.g.
--
--
newtype PsqlType
PsqlType :: Text -> PsqlType
[unPsqlType] :: PsqlType -> Text
-- | Execute a query against a PostgreSQL database connection.
query :: (MonadIO m, Render query, ToRow (ArgsType query), FromRow (ResultType query)) => Connection -> Proxy query -> ArgsType query -> m [ResultType query]
-- | Execute a statement.
execute :: (MonadIO m, ToRow (ArgsType query), Render query) => Connection -> Proxy query -> ArgsType query -> m Int64
-- | Create the indicated table in the database.
--
-- See createTableStatement for details.
createTable :: forall proxy1 proxy2 key table m. (KnownSymbol (Name table), HasPsqlTypes (DBSchema table), HasFields (DBSchema table), HasFields key, IsSubset key (DBSchema table) ~ 'True, MonadIO m) => Connection -> proxy1 key -> proxy2 table -> m ()
-- | Produce the statement used to create a table.
--
-- In this example, we create an employee table with a multi-part primary
-- key, one nullable field, and a few non-nullable fields.
--
--
-- data Employee
-- instance Table Employee where
-- type Name = "employees"
-- type DBSchema =
-- Field "company_id" Int
-- :> Field "id" Int
-- :> Field "name" Text
-- :> Field "quit_date" (Maybe Day)
--
-- let
-- primaryKey :: Proxy '["company_id", "id"]
-- primaryKey = Proxy
--
-- table :: Proxy Employee
-- table = Proxy
--
-- in
-- createTableStatement primaryKey table
--
--
-- This will produce the statement:
--
--
-- "create table employees (company_id integer not null, id integer not null, name text not null, quit_date date, primary key (company_id, id));"
--
createTableStatement :: forall proxy1 proxy2 table key. (KnownSymbol (Name table), HasPsqlTypes (DBSchema table), HasFields (DBSchema table), HasFields key, IsSubset key (DBSchema table) ~ 'True) => proxy1 key -> proxy2 table -> Text
class HasFields a
class HasPsqlTypes a
class HasIsNullable a
-- | Make sure the fields in the list are actually part of the schema.
type family IsSubset fields schema
-- | Like FromRow, but defined here so we can avoid orphaned
-- instances.
class FromRow a
-- | Like ToRow, but defined here to avoid orphan instances.
class ToRow a
instance Data.String.IsString Database.Ribbit.PostgreSQL.PsqlType
instance Database.Ribbit.PostgreSQL.FromRow a => Database.PostgreSQL.Simple.FromRow.FromRow (Database.Ribbit.PostgreSQL.Wrap a)
instance Database.Ribbit.PostgreSQL.ToRow a => Database.PostgreSQL.Simple.ToRow.ToRow (Database.Ribbit.PostgreSQL.Wrap a)
instance (Database.Ribbit.PostgreSQL.ToRow a, Database.Ribbit.PostgreSQL.ToRow b) => Database.Ribbit.PostgreSQL.ToRow (a Database.Ribbit.:> b)
instance Database.PostgreSQL.Simple.ToField.ToField a => Database.Ribbit.PostgreSQL.ToRow (Data.Tuple.Only.Only a)
instance Database.Ribbit.PostgreSQL.ToRow ()
instance (Database.Ribbit.PostgreSQL.FromRow a, Database.Ribbit.PostgreSQL.FromRow b) => Database.Ribbit.PostgreSQL.FromRow (a Database.Ribbit.:> b)
instance Database.PostgreSQL.Simple.FromField.FromField a => Database.Ribbit.PostgreSQL.FromRow (Data.Tuple.Only.Only a)
instance forall k1 k2 (typ :: k2) (name :: k1). (Database.Ribbit.PostgreSQL.HasIsNullable typ, Database.Ribbit.PostgreSQL.HasPsqlType typ) => Database.Ribbit.PostgreSQL.HasPsqlTypes (Database.Ribbit.Field name typ)
instance forall k1 k2 (typ :: k2) more (name :: k1). (Database.Ribbit.PostgreSQL.HasIsNullable typ, Database.Ribbit.PostgreSQL.HasPsqlType typ, Database.Ribbit.PostgreSQL.HasPsqlTypes more) => Database.Ribbit.PostgreSQL.HasPsqlTypes (Database.Ribbit.Field name typ Database.Ribbit.:> more)
instance Database.Ribbit.PostgreSQL.HasPsqlType a => Database.Ribbit.PostgreSQL.HasPsqlType (GHC.Maybe.Maybe a)
instance Database.Ribbit.PostgreSQL.HasPsqlType Data.Text.Internal.Text
instance Database.Ribbit.PostgreSQL.HasPsqlType GHC.Types.Int
instance Database.Ribbit.PostgreSQL.HasPsqlType Data.Time.Calendar.Days.Day
instance Database.Ribbit.PostgreSQL.HasIsNullable (GHC.Maybe.Maybe a)
instance forall k (a :: k). Database.Ribbit.PostgreSQL.HasIsNullable a
instance forall k (name :: GHC.Types.Symbol) (typ :: k). GHC.TypeLits.KnownSymbol name => Database.Ribbit.PostgreSQL.HasFields (Database.Ribbit.Field name typ)
instance forall k (name :: GHC.Types.Symbol) more (typ :: k). (GHC.TypeLits.KnownSymbol name, Database.Ribbit.PostgreSQL.HasFields more) => Database.Ribbit.PostgreSQL.HasFields (Database.Ribbit.Field name typ Database.Ribbit.:> more)
instance Database.Ribbit.PostgreSQL.HasFields '[]
instance (GHC.TypeLits.KnownSymbol name, Database.Ribbit.PostgreSQL.HasFields more) => Database.Ribbit.PostgreSQL.HasFields (name : more)