Safe Haskell  None 

Language  Haskell2010 
 data Association a b = Association {
 assocSelect :: !(DBSelect (a :. b))
 assocSelectOnlyB :: !(DBSelect b)
 assocWhereQuery :: !Query
 assocWhereParam :: !(a > [Action])
 assocProject :: Model b => Association a b > DBSelect b
 assocWhere :: Model b => Association a b > a > DBSelect b
 findAssoc :: Model b => Association a b > Connection > a > IO [b]
 data GDBRefInfo reftype child parent = DBRefInfo {
 dbrefSelector :: !(child > GDBRef reftype parent)
 dbrefQColumn :: !ByteString
 type DBRefInfo = GDBRefInfo NormalRef
 defaultDBRefInfo :: forall child parent. (Model child, Model parent, GetField ExtractRef child (DBRef parent)) => DBRefInfo child parent
 dbrefAssocs :: forall child parent rt. (Model child, Model parent) => GDBRefInfo rt child parent > (Association child parent, Association parent child)
 has :: (Model child, Model parent, GetField ExtractRef child (DBRef parent)) => Association parent child
 belongsTo :: (Model child, Model parent, GetField ExtractRef child (DBRef parent)) => Association child parent
 data JoinTable a b = JoinTable {
 jtTable :: !ByteString
 jtColumnA :: !ByteString
 jtColumnB :: !ByteString
 defaultJoinTable :: forall a b. (Model a, Model b) => JoinTable a b
 jtAssocs :: (Model a, Model b) => JoinTable a b > (Association a b, Association b a)
 joinTable :: (Model a, Model b) => Association a b
 jtAdd :: (Model a, Model b) => JoinTable a b > Connection > a > b > IO Bool
 jtRemove :: (Model a, Model b) => JoinTable a b > Connection > a > b > IO Bool
 jtRemoveByRef :: (Model a, Model b) => JoinTable a b > Connection > GDBRef rt a > GDBRef rt b > IO Bool
 jtAddStatement :: JoinTable a b > Query
 jtRemoveStatement :: JoinTable a b > Query
 jtParam :: (Model a, Model b) => JoinTable a b > a > b > [Action]
 jtFlip :: JoinTable a b > JoinTable b a
 jtAssoc :: forall a b. (Model a, Model b) => JoinTable a b > Association a b
 nestAssoc :: (Model a, Model b) => Association a b > Association b c > Association a (b :. c)
 chainAssoc :: (Model a, Model b, Model c) => Association a b > Association b c > Association a c
Documentation
data Association a b Source #
A data structure representing a relationship between a model a
and a model b
. At a high level, an Association a b
tells you
how to find rows of type b
given rows of type a
. More
concretely, this boils down to being able to make two types of
query.
 You want to look up a bunch of
(a
s, filtering using predicates on both:.
b)a
andb
(e.g., get a list of recent posts and their authors). For this purpose, you can useassocSelect
, which allows you toaddWhere
predicates mentioning columns in botha
andb
.  You already have an instance of type
a
, and want to find all theb
s associated with it. For that you use eitherassocWhere
orfindAssoc
(which internally access fieldsassocSelectOnlyB
,assocWhereQuery
, andassocWhereParam
). This type of query is strictly less general than the first one, but can be formulated in a more efficient way by extracting values directly from a concrete instance ofa
without needing to touch tablea
in the database.
Note that an Association
is asymmetric. It tells you how to get
b
s from a
s, but not vice versa. In practice, there will almost
always be an association in the other direction, too. Functions
such as dbrefAssocs
and jtAssocs
therefore create an
Association
and its inverse simultaneously, returning them as a
pair.
Association  

Show (Association a b) Source #  
assocProject :: Model b => Association a b > DBSelect b Source #
A projection of assocSelect
, extracting only the fields of
model b
. Note that this query touches table a
even if it does
not return results from a
. Hence, you can use addWhere
to add
predicates on both a
and b
. (Note the contrast to
assocSelectOnlyB
, which does not touch table a
at all, and
hence in the case of an INNER JOIN
might return rows of b
that
should not be part of the association. assocSelectOnlyB
is
intended for use only in conjunction with assocWhereQuery
.)
assocWhere :: Model b => Association a b > a > DBSelect b Source #
Returns a DBSelect
for all b
s associated with a particular
a
.
findAssoc :: Model b => Association a b > Connection > a > IO [b] Source #
Follow an association to return all of the b
s associated
with a particular a
. The behavior is similar to:
findAssoc' ab c a = dbSelect c $ assocWhere ab a
But if the first argument is a static association, this function may be marginally faster because it prerenders most of the query.
Associations based on parentchild relationships
data GDBRefInfo reftype child parent Source #
A common type of association is when one model contains a DBRef
or DBRefUnique
pointing to another model. In this case, the
model containing the DBRef
is known as the child, and the
referenced model is known as the parent.
Two pieces of information are required to describe a parentchild
relationship: First, the field selector that extracts the Haskell
DBRef
from the haskell type child
, and second the name of the
database column that stores this DBRef
field.
For example, consider the following:
data Author = Author { authorId :: DBKey } deriving (Show, Generic) instance Model Author data Post = Post { postId :: DBKey , postAuthorId :: DBRef Author } deriving (Show, Generic) instance Model Post post_author_refinfo :: DBRefInfo Post Author post_author_refinfo = DBRefInfo { dbrefSelector = postAuthorId , dbrefQColumn = "\"post\".\"postAuthorId\"" }
Note that the parentchild relationship described by a GDBRefInfo
is asymmetric, but bidirectional. When a
exists, the schema should generally not permit the
existence of a valid DBRefInfo
child
parent
structure.
However, the DBRefInfo
parent childdbrefAssocs
function generates Association
s in
both directions from a single DBRefInfo
.
Constructing such parentchild Association
s requires knowing how
to extract primary keys from the parent
type as well as the name
of the column storing primary keys in parent
. Fortunately, this
information is already available from the Model
class, and thus
does not need to be in the GDBRefInfo
. (Most functions on
GDBRefInfo
s require parent
and child
to be instances of
Model
.)
When your Model
s are instances of Generic
(which will usually
be the case), a DBRefInfo
structure can be computed automatically
by defaultDBRefInfo
. This is the recommended way to produce a
GDBRefInfo
. (Alternatively, see has
and belongsTo
to make
use of an entirely implicit DBRefInfo
.)
DBRefInfo  

Show (GDBRefInfo rt c p) Source #  
type DBRefInfo = GDBRefInfo NormalRef Source #
DBRefInfo
is a type alias for the common case that the
reference in a GDBRefInfo
is a DBRef
(as opposed to a
DBRefUnique
). The functions in this library do not care what
type of reference is used. The type is generalized to GDBRefInfo
just to make it easier to assign a selector to dbrefSelector
when
the selector returns a DBRefUnique
. Note, however, that
defaultDBRefInfo
returns a DBRefInfo
regardless of the flavor
of reference actually encountered.
defaultDBRefInfo :: forall child parent. (Model child, Model parent, GetField ExtractRef child (DBRef parent)) => DBRefInfo child parent Source #
Creates a DBRefInfo
from a model child
that references
parent
. For this to work, the child
type must be an instance
of Generic
and must contain exactly one field of the any of the
following types:
, which matches bothGDBRef
rt parent
andDBRef
parent
.DBRefUnique
parentMaybe (
, for cases where the reference might beGDBRef
rt parent)NULL
. Note, however, that an exception will be thrown if you callfindAssoc
on a child whose reference isNothing
.
A special case arises when a Model contains a DBRef
to itself.
If you just wish to find parents and children given an existing
structure (i.e., findAssoc
), it is okay to declare an
. However, in this case attempts to
use Association
MyType MyTypeassocSelect
will then fail. To work around this problem, the
parent must use a row alias.
Note that currently aliasing the child will not work, since the
As
data structure will not contain a DBRef
field, only the
contents of the As
data structure. An example of doing this
correctly (using has
and belongsTo
, both of which wrap
defaultDBRefInfo
):
data Bar = Bar { barId :: !DBKey , barName :: !String , barParent :: !(Maybe (DBRef Bar)) } deriving (Show, Generic) instance Model Bar where modelInfo = underscoreModelInfo "bar" data ParentBar = ParentBar instance RowAlias ParentBar where rowAliasName _ = "parent_bar" toParent :: Association Bar (As ParentBar Bar) toParent = belongsTo toChild :: Association (As ParentBar Bar) Bar toChild = has
dbrefAssocs :: forall child parent rt. (Model child, Model parent) => GDBRefInfo rt child parent > (Association child parent, Association parent child) Source #
Generate both the childparent and parentchild Association
s
implied by a GDBRefInfo
.
has :: (Model child, Model parent, GetField ExtractRef child (DBRef parent)) => Association parent child Source #
Short for
snd $ dbrefAssocs defaultDBRefInfo
Note the inverse Association
is given by belongsTo
. For
example, given the Author
and Post
models described in the
documentation for GDBRefInfo
, in which each Post
references an
Author
, you might say:
author_post :: Association Author Post author_post = has post_author :: Association Post Author post_author = belongsTo
belongsTo :: (Model child, Model parent, GetField ExtractRef child (DBRef parent)) => Association child parent Source #
Join table Associations
A data structure representing a dedicated join table in the database. A join table differs from a model in that rows do not have primary keys. Hence, model operations do not apply. Nonetheless a join table conveys information about a relationship between models.
Note that all names in a JoinTable
should be unquoted.
JoinTable  

defaultJoinTable :: forall a b. (Model a, Model b) => JoinTable a b Source #
The default join table has the following fields:
jtName
is the name of the two models (in alphabetical order), separated by an'_'
character.jtColumnA
is the name of modela
, an'_'
character, and the name of the primary key column in tablea
.jtColumnB
is the name of modelb
, an'_'
character, and the name of the primary key column in tableb
.
Note that defaultJoinTable
cannot create a default join table for
joining a model to itself, as following these rules the two columns
would have the same name. If you wish to join a table to itself,
you have two options: First, you can define the join table and
assign the column names manually. This will permit you to call
findAssoc
, but you still will not be able to use assocSelect
for more complex queries, since SQL does not permit joins between
two tables with the same name. The second option is to give one of
the sides of the join table a row alias with As
. For example:
data ParentBar = ParentBar instance RowAlias ParentBar where rowAliasName _ = "parent_bar" selfJoinTable :: JoinTable Bar (As ParentBar Bar) selfJoinTable = defaultJoinTable selfJoin :: Association Bar (As ParentBar Bar) otherSelfJoin :: Association (As ParentBar Bar) Bar (selfJoin, otherSelfJoin) = jtAssocs selfJoinTable
jtAssocs :: (Model a, Model b) => JoinTable a b > (Association a b, Association b a) Source #
Generate the two associations implied by a JoinTable
.
joinTable :: (Model a, Model b) => Association a b Source #
Generate a oneway association based on the default join table
naming scheme described at defaultJoinTable
. Defined as:
joinTable = jtAssoc defaultJoinTable
For example:
aToB :: Association A B aToB = joinTable bToA :: Association B A bToA = joinTable
Operations on join tables
jtAdd :: (Model a, Model b) => JoinTable a b > Connection > a > b > IO Bool Source #
Add an association between two models to a join table. Returns
True
if the association was not already there.
jtRemove :: (Model a, Model b) => JoinTable a b > Connection > a > b > IO Bool Source #
Remove an association from a join table. Returns True
if the
association was previously there.
jtRemoveByRef :: (Model a, Model b) => JoinTable a b > Connection > GDBRef rt a > GDBRef rt b > IO Bool Source #
Remove an assocation from a join table when you don't have the target instances of the two models handy, but do have references.
Semiinternal join table functions
jtAddStatement :: JoinTable a b > Query Source #
A SQL statement suitable for adding a pair to a join table. Note
that the statement takes two parameters (i.e., contains two '?'
characters) corresponding to the primary keys of the two models
being associated. These parameters can be supplied by jtParam
.
jtRemoveStatement :: JoinTable a b > Query Source #
A SQL statement for removing a pair from a join table. Like
jtAddStatement
, the query is parameterized by two primary keys.
jtParam :: (Model a, Model b) => JoinTable a b > a > b > [Action] Source #
Generate parameters for jtAddStatement
and jtRemoveStatement
.
The returned list is suitable for use as a ToRow
instance. For
example:
execute conn (jtAddStatement my_join_table) (jtParam a b)
jtFlip :: JoinTable a b > JoinTable b a Source #
Flip a join table. This doesn't change the name of the table (since the same join table is used in both directions, and the default join table name glues together the two model names in alphabetical order anyway).
Nested and chained associations
nestAssoc :: (Model a, Model b) => Association a b > Association b c > Association a (b :. c) Source #
Combine two associations into one.
chainAssoc :: (Model a, Model b, Model c) => Association a b > Association b c > Association a c Source #
Combine two associations into one, and project away the middle
type. (The middle type can still be mentioned in WHERE
clauses.)
An example:
data Author = Author { authorId :: DBKey } deriving (Show, Generic) instance Model Author where modelInfo = underscoreModelInfo "author" data Post = Post { postId :: DBKey , postAuthorId :: DBRef Author } deriving (Show, Generic) instance Model Post where modelInfo = underscoreModelInfo "post" data Comment = Comment { commentId :: DBKey , commentPostId :: DBRef Post } deriving (Show, Generic) instance Model Comment where modelInfo = underscoreModelInfo "comment" author_posts :: Association Author Post post_author :: Association Post Author (post_author, author_posts) = dbrefAssocs defaultDBRefInfo  Could equally well use dbrefAssocs as above post_comments :: Association Post Comment post_comments = has comment_post :: Association Comment Post comment_post = belongsTo comment_author :: Association Comment Author comment_author = chainAssoc comment_post post_author author_comments :: Association Author Comment author_comments = chainAssoc author_posts post_comments