@@ -2,19 +2,24 @@ module ProjectM36.IsomorphicSchema where
22import ProjectM36.Base
33-- isomorphic schemas offer bi-directional functors between two schemas
44
5+--TODO: rel attrs rename or transform (needs bidirectional atom functions)
6+
7+-- the isomorphic building blocks should not be arbitrarily combined; for example, combing restrict and union on the same target relvar does not make sense as that would create effects at a distance in the secondary schema
58--this should create a new schema
6−data IsomorphSchema = IsoRelVarName RelVarName RelVarName | --maps relvar names between schemas
9+data SchemaIsomorph = IsoRelVarName RelVarName RelVarName | --maps relvar names between schemas
710 IsoRestrict RelVarName RestrictionPredicateExpr (RelVarName,RelVarName) | --maps one relvar into two relvars (true, false)
811 IsoUnion (RelVarName, RelVarName) RestrictionPredicateExpr RelVarName --maps two relvars to one relvar
912 -- IsoTypeConstructor in morphAttrExpr
13+
14+type SchemaIsomorphs = [SchemaIsomorph]
1015
1116{-
12−invert :: IsomorphSchema -> IsomorphSchema
17+invert :: SchemaIsomorph -> SchemaIsomorph
1318invert (IsoRelVarName nameA nameB) = IsoRelVarName nameB nameA
1419-}
1520
1621-- | Morph a relational expression in one schema to another isomorphic schema.
17−relExprMorph :: IsomorphSchema -> (RelationalExpr -> RelationalExpr)
22+relExprMorph :: SchemaIsomorph -> (RelationalExpr -> RelationalExpr)
1823-- wherever nameA is found in the expr, it must be replaced by nameB
1924relExprMorph (IsoRelVarName nameA nameB) = \expr -> case expr of
2025 RelationVariable rv () | rv == nameA -> RelationVariable nameB ()
@@ -46,7 +51,7 @@ spam = relExprMogrify (relExprMorph (IsoRestrict "emp" TruePredicate ("nonboss",
4651spam2 :: RelationalExpr
4752spam2 = relExprMogrify (relExprMorph (IsoUnion ("boss", "nonboss") TruePredicate "emp")) (RelationVariable "boss" ())
4853
49−databaseContextExprMorph :: IsomorphSchema -> (DatabaseContextExpr -> DatabaseContextExpr)
54+databaseContextExprMorph :: SchemaIsomorph -> (DatabaseContextExpr -> DatabaseContextExpr)
5055databaseContextExprMorph iso@(IsoRelVarName nameA nameB) = \expr -> case expr of
5156 Define rv attrExprs | rv == nameA -> Define nameB attrExprs
5257 Undefine rv | rv == nameA -> Undefine nameB
@@ -78,16 +83,26 @@ databaseContextExprMorph iso@(IsoUnion (rvTrue, rvFalse) filt rvOut) = \expr ->
7883 --assign: replace all instances in the portion of the target relvar with the new tuples from the relExpr
7984 --problem: between the delete->insert, constraints could be violated which would not otherwise be violated in the "in" schema. This implies that there should be a combo operator which can insert/update/delete in a single pass based on relexpr queries, or perhaps MultipleExpr should be the infamous "comma" operator from TutorialD?
8085 Assign rv relExpr | rv == rvTrue -> MultipleExpr [Delete rvOut filt,
81− Insert rvOut (Restrict filt relExpr)]
86+ Insert rvOut (Restrict filt (relExprF relExpr))]
8287 Assign rv relExpr | rv == rvFalse -> MultipleExpr [Delete rvOut (NotPredicate filt),
83− Insert rvOut (Restrict (NotPredicate filt) relExpr)]
84− Insert rv relExpr | rv == rvTrue || rv == rvFalse -> Insert rvOut relExpr
88+ Insert rvOut (Restrict (NotPredicate filt) (relExprF relExpr))]
89+ Insert rv relExpr | rv == rvTrue || rv == rvFalse -> Insert rvOut (relExprF relExpr)
8590 Delete rv delPred | rv == rvTrue -> Delete rvOut (AndPredicate delPred filt)
8691 Delete rv delPred | rv == rvFalse -> Delete rvOut (AndPredicate delPred (NotPredicate filt))
8792 Update rv attrMap predi | rv == rvTrue -> Update rvOut attrMap (AndPredicate predi filt)
8893 Update rv attrMap predi | rv == rvFalse -> Update rvOut attrMap (AndPredicate (NotPredicate filt) predi)
8994 orig -> orig
95+ where
96+ relExprF = relExprMogrify (relExprMorph iso)
97+
9098databaseContextExprMogrify :: (DatabaseContextExpr -> DatabaseContextExpr) -> DatabaseContextExpr -> DatabaseContextExpr
9199databaseContextExprMogrify func (MultipleExpr exprs) = func (MultipleExpr (map func exprs))
92100databaseContextExprMogrify func orig = func orig
93101
102+-- | Apply the isomorphism transformations to the relational expression to convert the relational expression from operating on one schema to a disparate, isomorphic schema.
103+applyRelationalExprSchemaIsomorphs :: SchemaIsomorphs -> RelationalExpr -> RelationalExpr
104+applyRelationalExprSchemaIsomorphs morphs expr = foldl (\expr' morph -> relExprMogrify (relExprMorph morph) expr') expr morphs
105+
106+-- | Apply the isomorphism transformations to the database context expression to convert the expression from operating on one schema to a disparate, isomorphic schema.
107+applyDatabaseCotextExprSchemaIsomorphs :: SchemaIsomorphs -> DatabaseContextExpr -> DatabaseContextExpr
108+applyDatabaseCotextExprSchemaIsomorphs morphs expr = foldl (\expr' morph -> databaseContextExprMogrify (databaseContextExprMorph morph) expr') expr morphs