With the age of this question, it is probably too late of an answer to make any difference to you, but maybe if some other person comes along with a similar problem…
It comes down to the fact that it cannot be inferred that you want entity
to refer to Book
when branch
is used in masterHead
. The part of the error message that reads
The choice depends on the instantiation of `entity0′
tells you where you need to remove the ambiguity, specifically that you need to give more information about what entity0
should be. You can give some type annotations to help things out.
First, define branch
as
type BranchTable entity = Table (RecCons (Revision entity) (Expr (Revision entity)) RecNil)
branch :: BrancTable entity
branch = baseTable "branch" $ hdbMakeEntry undefined
and then change masterHead
to read
masterHead :: Query (Rel (RecCons (Revision Book) (Expr (Revision Book)) RecNil))
masterHead = do
revisions <- table bookRevision
branches <- table (branch :: BranchTable Book)
restrict $ revisions ! revIdField .==. branches ! revIdField
return revisions
Note the type annotation applied to branch
: branch :: BranchTable Book
which serves to remove the ambiguity that was causing the type error.
To make masterHead
applicable to anything with a Revision e
field in it, you can use this definition:
masterHead :: (ShowRecRow r, HasField (Revision e) r) => Table r -> e -> Query (Rel r)
masterHead revTable et =
do revisions <- table revTable
branches <- table branch'
restrict $ revisions ! revIdField' .==. branches ! revIdField'
return revisions
where (branch', revIdField') = revBundle revTable et
revBundle :: HasField (Revision e) r => Table r -> e -> (BranchTable e, Attr (Revision e) (Revision e))
revBundle table et = (branch, revIdField)
The et
argument is needed to specify what the e
type should be and can just be undefined
ascribed to the proper type as in
masterHead bookRevision (undefined :: Book)
which generates the SQL
SELECT rev_id1 as rev_id
FROM (SELECT rev_id as rev_id2
FROM branch as T1) as T1,
(SELECT rev_id as rev_id1
FROM book_revision as T1) as T2
WHERE rev_id1 = rev_id2
this does require FlexibleContexts
though, but it can be applied to the asker’s module without recompiling HaskellDB.