@@ -7,6 +7,7 @@ import Control.Monad
7import GHC.Generics
7import GHC.Generics
8import Data.Binary
8import Data.Binary
9import qualified Data.Map as M
9import qualified Data.Map as M
10+import qualified Data.Set as S
10-- isomorphic schemas offer bi-directional functors between two schemas
11-- isomorphic schemas offer bi-directional functors between two schemas
12--TODO: note that renaming a relvar should alter any stored isomorphisms as well
13--TODO: note that renaming a relvar should alter any stored isomorphisms as well
@@ -25,18 +26,47 @@ isFullyIsomorphic :: SchemaIsomorph -> Bool
25isFullyIsomorphic (IsoRestrict _ _ (a, b)) = isJust a && isJust b
26isFullyIsomorphic (IsoRestrict _ _ (a, b)) = isJust a && isJust b
26isFullyIsomorphic (IsoUnion (_, a) _ _) = isJust a
27isFullyIsomorphic (IsoUnion (_, a) _ _) = isJust a
29+isomorphs :: Schema -> SchemaIsomorphs
30+isomorphs (Schema i) = i
28-- | Convenience function which renames a relvar in schemaA to another name in schemaB.
32-- | Convenience function which renames a relvar in schemaA to another name in schemaB.
29isomorphRename :: RelVarName -> RelVarName -> SchemaIsomorph
33isomorphRename :: RelVarName -> RelVarName -> SchemaIsomorph
30isomorphRename nameA nameB = IsoRestrict nameA TruePredicate (Just nameB, Nothing)
34isomorphRename nameA nameB = IsoRestrict nameA TruePredicate (Just nameB, Nothing)
32−isomorphHide :: RelVarName -> SchemaIsomorph
36+{- -- useful for transforming a concrete context into a virtual schema and vice versa
33−isomorphHide nameA = IsoRestrict nameA (NotPredicate TruePredicate) (Nothing, Nothing)
36invert :: SchemaIsomorph -> SchemaIsomorph
37invert :: SchemaIsomorph -> SchemaIsomorph
37invert (IsoRelVarName nameA nameB) = IsoRelVarName nameB nameA
38invert (IsoRelVarName nameA nameB) = IsoRelVarName nameB nameA
41+isomorphInRelVarNames :: SchemaIsomorph -> [RelVarName]
42+isomorphInRelVarNames (IsoRestrict rv _ _) = [rv]
43+isomorphInRelVarNames (IsoUnion (rvA, mRvB) _ _) = rvA : maybe [] (\x -> [x]) mRvB
45+-- | Relation variables names represented in the virtual schema space. Useful for determining if a relvar name is valid in the schema.
46+isomorphsInRelVarNames :: SchemaIsomorphs -> S.Set RelVarName
47+isomorphsInRelVarNames morphs = S.fromList (foldr rvnames [] morphs)
49+ rvnames morph acc = acc ++ isomorphInRelVarNames morph
51+isomorphOutRelVarNames :: SchemaIsomorph -> [RelVarName]
52+isomorphOutRelVarNames (IsoRestrict _ _ (mRvA, mRvB)) = catMaybes [mRvA, mRvB]
53+isomorphOutRelVarNames (IsoUnion _ _ rvA) = [rvA]
55+isomorphsOutRelVarNames :: SchemaIsomorphs -> S.Set RelVarName
56+isomorphsOutRelVarNames morphs = S.fromList (foldr rvnames [] morphs)
58+ rvnames morph acc = acc ++ isomorphOutRelVarNames morph
60+processRelationalExprInSchema :: Schema -> RelationalExpr -> Either RelationalError RelationalExpr
61+processRelationalExprInSchema (Schema morphs) relExprIn = do
62+ let validRelVarNames = isomorphsInRelVarNames morphs
63+ --validate that all rvs are present in the virtual schema- this prevents relation variables being referenced in the underlying schema (falling through the transformation)
64+ let processRelExpr rexpr morph = relExprMogrify (\expr -> case expr of
65+ RelationVariable rv () | S.notMember rv validRelVarNames -> Left (RelVarNotDefinedError rv)
66+ ex -> relExprMorph morph ex) rexpr
68+ foldM processRelExpr relExprIn morphs
40-- | Morph a relational expression in one schema to another isomorphic schema.
70-- | Morph a relational expression in one schema to another isomorphic schema.
41relExprMorph :: SchemaIsomorph -> (RelationalExpr -> Either RelationalError RelationalExpr)
71relExprMorph :: SchemaIsomorph -> (RelationalExpr -> Either RelationalError RelationalExpr)
42relExprMorph (IsoRestrict relIn predi split) = \expr -> case expr of
72relExprMorph (IsoRestrict relIn predi split) = \expr -> case expr of
@@ -162,9 +192,17 @@ inclusionDependenciesMorph iso = \(InclusionDependency subExpr expr) -> Inclusio
162applyInclusionDependenciesSchemaIsoMorphs :: SchemaIsomorphs -> InclusionDependencies -> Either RelationalError InclusionDependencies
192applyInclusionDependenciesSchemaIsoMorphs :: SchemaIsomorphs -> InclusionDependencies -> Either RelationalError InclusionDependencies
163--add inc deps for restriction with some automatic name
193--add inc deps for restriction with some automatic name
164applyInclusionDependenciesSchemaIsoMorphs morphs incDeps = undefined
194applyInclusionDependenciesSchemaIsoMorphs morphs incDeps = undefined
198+data DatabaseContext =
166applyRelationVariablesSchemaIsomorphs :: SchemaIsomorphs -> RelationVariables -> Either RelationalError RelationVariables
203applyRelationVariablesSchemaIsomorphs :: SchemaIsomorphs -> RelationVariables -> Either RelationalError RelationVariables
167applyRelationVariablesSchemaIsomorphs = undefined
204applyRelationVariablesSchemaIsomorphs = undefined
169applySchemaIsomorphsToDatabaseContext :: SchemaIsomorphs -> DatabaseContext -> Either RelationalError DatabaseContext
207applySchemaIsomorphsToDatabaseContext :: SchemaIsomorphs -> DatabaseContext -> Either RelationalError DatabaseContext
170applySchemaIsomorphsToDatabaseContext morphs context = do
208applySchemaIsomorphsToDatabaseContext morphs context = do
@@ -176,16 +214,29 @@ applySchemaIsomorphsToDatabaseContext morphs context = do
176 --notifications = notifs,
214 --notifications = notifs,
177 --typeConstructorMapping = tconsmapping
215 --typeConstructorMapping = tconsmapping
218+validate :: SchemaIsomorph -> S.Set RelVarName -> Either RelationalError SchemaIsomorph
219+validate morph underlyingRvNames = if S.size invalidRvNames > 0 then
220+ Left (MultipleErrors (map RelVarNotDefinedError (S.toList invalidRvNames)))
224+ morphRvNames = S.fromList (isomorphOutRelVarNames morph)
225+ invalidRvNames = S.difference morphRvNames underlyingRvNames
227+-- the second argument really should be a database context in the future so we can morph other context items
180−evalSchemaExpr :: SchemaExpr -> Subschemas -> Either RelationalError Subschemas
228+evalSchemaExpr :: SchemaExpr -> S.Set RelVarName -> Subschemas -> Either RelationalError Subschemas
181−evalSchemaExpr (AddSubschema sname) sschemas = if M.member sname sschemas then
229+evalSchemaExpr (AddSubschema sname) _ sschemas = if M.member sname sschemas then
182 Left (SubschemaNameInUseError sname)
230 Left (SubschemaNameInUseError sname)
184 pure (M.insert sname (Schema []) sschemas)
232 pure (M.insert sname (Schema []) sschemas)
185−evalSchemaExpr (AddSubschemaIsomorph sname morph) sschemas = case M.lookup sname sschemas of
233+evalSchemaExpr (AddSubschemaIsomorph sname morph) underlyingRvNames sschemas = case M.lookup sname sschemas of
186 Nothing -> Left (SubschemaNameNotInUseError sname)
234 Nothing -> Left (SubschemaNameNotInUseError sname)
235+ Just (Schema oldMorphs) -> do
236+ morph' <- validate morph underlyingRvNames
187− Just (Schema oldMorphs) -> pure (M.insert sname (Schema (oldMorphs ++ [morph])) sschemas)
237+ pure (M.insert sname (Schema (oldMorphs ++ [morph'])) sschemas)
188−evalSchemaExpr (RemoveSubschema sname) sschemas = if M.member sname sschemas then
238+evalSchemaExpr (RemoveSubschema sname) _ sschemas = if M.member sname sschemas then
189 pure (M.delete sname sschemas)
239 pure (M.delete sname sschemas)
191 Left (SubschemaNameNotInUseError sname)
241 Left (SubschemaNameNotInUseError sname)