[Haskell-cafe] Fwd: Attempt at defining typeful primary key/foreign key relationships

Justin Bailey jgbailey at gmail.com
Mon Dec 31 15:30:41 EST 2007


Small correction - the extensions listed at the bottom weren't
necessary. I had attempted to define a relationship among tables
automatically as:

  instance (HasField fk child, HasField pk parent, HasRelation pk fk)
=> HasRelation parent child

But that was redundant with the signature on relation. Removing it
allowed me to remove all extensions except MultiParameterTypeClasses.

Justin

---------- Forwarded message ----------
From: Justin Bailey <jgbailey at gmail.com>
Date: Dec 31, 2007 12:25 PM
Subject: Attempt at defining typeful primary key/foreign key relationships
To: haskelldb-users at lists.sourceforge.net


All,

As part of my data model, I'd like to say there is a primary
key/foreign key relationship between two tables/queries. Right now I
only want to do this to capture some extra-query information that I'm
using for code generation - I don't intend it to actually affect
queries generated, though I'd like to go there eventually.

I define a class which says there is a relation:

 class HasRelation pk fk

I define a type which holds relation values:

  data Relation a pk fk p c = Relation { ... }

Relation values can only be constructed by a function with appropriate
constraints on it:

  relation :: (HasRelation pk fk, HasField pk parent, HasField fk
child) => Attr pk a -> Attr fk a -> Rel parent -> Rel child ->
Relation a pk fk parent child
  relation primaryKey foreignKey prnt chld = Relation ....

As an example, if I have tables Orders and LineItems, both with field
order_id, I can establish a relationship by first defining an
instance:

  instance HasRelation Orders.Order_id LineItems.Order_id

I can then create a relation value between the two:

  orders <- table Orders.orders
  lineItems <- table LineItems.lineItems
  let r1 = relation Orders.order_id LineItems.order_id orders lineitems

Note these types would be defined using DBDirect, so Order_id as a
type with one constructor, lineItems has type "Table ...", etc. If I
try to define an incorrect relation (wrong fields, fields in the wrong
order, etc), then the above will not compile, which is just what I
want.

If you've read this far, I've not done any type-level programming or
even played much with classes and instances before so I'd like to know
if the approach makes sense. I took most of my inspiration from the
HasField class in the HDBRec module.

  1) Could this be simpler?  Any obvious deficiencies?
  2) I had to enable a number of extensions (though all of these are
also enabled by haskelldb) - FlexibleInstances, FlexibleContexts,
UndecidableInstances and OverlappingInstances. Should I be worried?
  3) It's possible to define relationships among any two types. How
can I limit that to 1) attributes with 2) the same type? Would I have
to define an Attr typeclass, parallel to the Attr type?

Thanks for any and all feedback. Happy New Year!

Justin


More information about the Haskell-Cafe mailing list