Safe Haskell | None |
---|---|
Language | Haskell2010 |
Build tables and database operations from (almost) any Haskell type.
While the types in this module may look somewhat intimidating, the rules for generic tables and queries are quite simple:
- Any record type with a single data constructor, where all fields are
instances of
SqlType
, can be used for generic tables and queries if it derivesGeneric
. - To use the standard functions from Database.Selda on a generic table,
it needs to be unwrapped using
gen
. - 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 tuple's corresponding type. - Relations obtained from a query can be re-assembled into their
corresponding data type using
fromRel
.
- type Relational a = (Generic a, GRelation (Rep a), GFromRel (Rep a), ToDyn (Relation a), Insert (Relation a))
- class Generic a
- data GenAttr a where
- newtype GenTable a = GenTable {}
- data Attribute
- type Relation a = Rel (Rep a)
- genTable :: forall a. Relational a => TableName -> [GenAttr a] -> GenTable a
- toRel :: Relational a => a -> Relation a
- toRels :: Relational a => [a] -> [Relation a]
- fromRel :: Relational a => Relation a -> a
- fromRels :: Relational a => [Relation a] -> [a]
- insertGen :: (Relational a, MonadSelda m) => GenTable a -> [a] -> m Int
- insertGen_ :: (Relational a, MonadSelda m) => GenTable a -> [a] -> m ()
- insertGenWithPK :: (Relational a, MonadSelda m) => GenTable a -> [a] -> m RowID
- primaryGen :: Attribute
- autoPrimaryGen :: Attribute
- uniqueGen :: Attribute
- fkGen :: Table t -> Selector t a -> Attribute
Documentation
type Relational a = (Generic a, GRelation (Rep a), GFromRel (Rep a), ToDyn (Relation a), Insert (Relation a)) Source #
Any type which has a corresponding relation.
To make a Relational
instance for some type, simply derive Generic
.
Note that only types which have a single data constructor, and where all
fields are instances of SqlValue
can be used with this module.
Attempting to use functions in this module with any type which doesn't
obey those constraints will result in a very confusing type error.
Representable types of kind *. This class is derivable in GHC with the DeriveGeneric flag on.
A generic column attribute.
Essentially a pair or a record selector over the type a
and a column
attribute.
type Relation a = Rel (Rep a) Source #
The relation corresponding to the given Haskell type. This relation simply corresponds to the fields in the data type, from left to right. For instance:
data Foo = Foo { bar :: Int , baz :: Text }
In this example, Relation Foo
is (Int :*: Text)
, as the first field
of Foo
has type Int
, and the second has type Text
.
genTable :: forall a. Relational a => TableName -> [GenAttr a] -> GenTable a Source #
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
columns.
For example:
data Person = Person { id :: Int , name :: Text , age :: Int , pet :: Maybe Text } deriving Generic people :: GenTable Person people = genTable "people" [(name, autoPrimaryGen)]
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.
toRel :: Relational a => a -> Relation a Source #
Convert a generic type into the corresponding database relation. A type's corresponding relation is simply the inductive tuple consisting of all of the type's fields.
data Person = Person { id :: Int , name :: Text , age :: Int , pet :: Maybe Text } deriving Generic somePerson = Person 0 "Velvet" 19 Nothing (theId :*: theName :*: theAge :*: thePet) = toRel somePerson
This is mainly useful when inserting values into a table using insert
and the other functions from Database.Selda.
toRels :: Relational a => [a] -> [Relation a] Source #
Convenient synonym for map toRel
.
fromRel :: Relational a => Relation a -> a Source #
Re-assemble a generic type from its corresponding relation. This can be done either for ad hoc queries or for queries over generic tables:
data SimplePerson = SimplePerson { name :: Text , age :: Int } deriving Generic demoPerson :: SimplePerson demoPerson = fromRel ("Miyu" :*: 10) adhoc :: Table (Text :*: Int) adhoc = table "adhoc" $ required "name" :*: required "age" getPersons1 :: MonadSelda m => m [SimplePerson] getPersons1 = map fromRel <$> query (select adhoc) generic :: GenTable SimplePerson generic = genTable "generic" [] getPersons2 :: MonadSelda m => m [SimplePerson] getPersons2 = map fromRel <$> query (select (gen generic))
Applying toRel
to an inductive tuple which isn't the corresponding
relation of the return type is a type error.
fromRels :: Relational a => [Relation a] -> [a] Source #
Convenient synonym for map fromRel
.
insertGen :: (Relational a, MonadSelda m) => GenTable a -> [a] -> m Int Source #
Like insert
, but accepts a generic table and its corresponding data type.
insertGen_ :: (Relational a, MonadSelda m) => GenTable a -> [a] -> m () Source #
Like insert_
, but accepts a generic table and its corresponding data type.
insertGenWithPK :: (Relational a, MonadSelda m) => GenTable a -> [a] -> m RowID Source #
Like insertWithPK
, but accepts a generic table and
its corresponding data type.
primaryGen :: Attribute Source #
A primary key which does not auto-increment.
autoPrimaryGen :: Attribute Source #
An auto-incrementing primary key.