From: Justin B. <jgb...@gm...> - 2007-12-31 20:25:22
|
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 |
From: Justin B. <jgb...@gm...> - 2007-12-31 20:58:26
|
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 <jgb...@gm...> Date: Dec 31, 2007 12:25 PM Subject: Attempt at defining typeful primary key/foreign key relationships To: has...@li... 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 |
From: Bjorn B. <bri...@cs...> - 2008-01-02 09:37:43
|
On Dec 31, 2007, at 21:25 , Justin Bailey wrote: Hi Justin, > 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 =3D 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) =3D> Attr pk a -> Attr fk a -> Rel parent -> Rel child -> > Relation a pk fk parent child > relation primaryKey foreignKey prnt chld =3D 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 =3D relation Orders.order_id LineItems.order_id orders =20 > 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? What's the purpose of the HasRelation class? Wouldn't just the =20 Relation type be enough? > 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? HaskellDB already uses most or all of those, so there's no need to =20 worry. > 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? Getting rid of HasRelation should solve this, AFAICT. But I haven't =20 thought this through in detail. You may also want to have a look at the CoddFish paper: http://=20 wiki.di.uminho.pt/twiki/bin/view/Research/PURe/CoddFish They do type-level programming to capture things like this. /Bj=F6rn |