@@ -7,6 +7,7 @@ import Control.Monad
77import GHC.Generics
88import Data.Binary
99import qualified Data.Map as M
10+import qualified Data.Set as S
1011-- isomorphic schemas offer bi-directional functors between two schemas
1112
1213--TODO: note that renaming a relvar should alter any stored isomorphisms as well
@@ -25,18 +26,47 @@ isFullyIsomorphic :: SchemaIsomorph -> Bool
2526isFullyIsomorphic (IsoRestrict _ _ (a, b)) = isJust a && isJust b
2627isFullyIsomorphic (IsoUnion (_, a) _ _) = isJust a
2728
29+isomorphs :: Schema -> SchemaIsomorphs
30+isomorphs (Schema i) = i
31+
2832-- | Convenience function which renames a relvar in schemaA to another name in schemaB.
2933isomorphRename :: RelVarName -> RelVarName -> SchemaIsomorph
3034isomorphRename nameA nameB = IsoRestrict nameA TruePredicate (Just nameB, Nothing)
3135
32−isomorphHide :: RelVarName -> SchemaIsomorph
33−isomorphHide nameA = IsoRestrict nameA (NotPredicate TruePredicate) (Nothing, Nothing)
34−
35−{-
36+{- -- useful for transforming a concrete context into a virtual schema and vice versa
3637invert :: SchemaIsomorph -> SchemaIsomorph
3738invert (IsoRelVarName nameA nameB) = IsoRelVarName nameB nameA
3839-}
3940
41+isomorphInRelVarNames :: SchemaIsomorph -> [RelVarName]
42+isomorphInRelVarNames (IsoRestrict rv _ _) = [rv]
43+isomorphInRelVarNames (IsoUnion (rvA, mRvB) _ _) = rvA : maybe [] (\x -> [x]) mRvB
44+
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)
48+ where
49+ rvnames morph acc = acc ++ isomorphInRelVarNames morph
50+
51+isomorphOutRelVarNames :: SchemaIsomorph -> [RelVarName]
52+isomorphOutRelVarNames (IsoRestrict _ _ (mRvA, mRvB)) = catMaybes [mRvA, mRvB]
53+isomorphOutRelVarNames (IsoUnion _ _ rvA) = [rvA]
54+
55+isomorphsOutRelVarNames :: SchemaIsomorphs -> S.Set RelVarName
56+isomorphsOutRelVarNames morphs = S.fromList (foldr rvnames [] morphs)
57+ where
58+ rvnames morph acc = acc ++ isomorphOutRelVarNames morph
59+
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
67+
68+ foldM processRelExpr relExprIn morphs
69+
4070-- | Morph a relational expression in one schema to another isomorphic schema.
4171relExprMorph :: SchemaIsomorph -> (RelationalExpr -> Either RelationalError RelationalExpr)
4272relExprMorph (IsoRestrict relIn predi split) = \expr -> case expr of
@@ -162,9 +192,17 @@ inclusionDependenciesMorph iso = \(InclusionDependency subExpr expr) -> Inclusio
162192applyInclusionDependenciesSchemaIsoMorphs :: SchemaIsomorphs -> InclusionDependencies -> Either RelationalError InclusionDependencies
163193--add inc deps for restriction with some automatic name
164194applyInclusionDependenciesSchemaIsoMorphs morphs incDeps = undefined
195+
196+{-
197+proposal
198+data DatabaseContext =
199+Concrete ...|
200+Virtual Isomorphs
201+-}
165202
166203applyRelationVariablesSchemaIsomorphs :: SchemaIsomorphs -> RelationVariables -> Either RelationalError RelationVariables
167204applyRelationVariablesSchemaIsomorphs = undefined
205+
168206
169207applySchemaIsomorphsToDatabaseContext :: SchemaIsomorphs -> DatabaseContext -> Either RelationalError DatabaseContext
170208applySchemaIsomorphsToDatabaseContext morphs context = do
@@ -176,16 +214,29 @@ applySchemaIsomorphsToDatabaseContext morphs context = do
176214 --notifications = notifs,
177215 --typeConstructorMapping = tconsmapping
178216 })
179−
180−evalSchemaExpr :: SchemaExpr -> Subschemas -> Either RelationalError Subschemas
181−evalSchemaExpr (AddSubschema sname) sschemas = if M.member sname sschemas then
217+
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)))
221+ else
222+ Right morph
223+ where
224+ morphRvNames = S.fromList (isomorphOutRelVarNames morph)
225+ invalidRvNames = S.difference morphRvNames underlyingRvNames
226+
227+-- the second argument really should be a database context in the future so we can morph other context items
228+evalSchemaExpr :: SchemaExpr -> S.Set RelVarName -> Subschemas -> Either RelationalError Subschemas
229+evalSchemaExpr (AddSubschema sname) _ sschemas = if M.member sname sschemas then
182230 Left (SubschemaNameInUseError sname)
183− else
231+ else
184232 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
186234 Nothing -> Left (SubschemaNameNotInUseError sname)
187− Just (Schema oldMorphs) -> pure (M.insert sname (Schema (oldMorphs ++ [morph])) sschemas)
188−evalSchemaExpr (RemoveSubschema sname) sschemas = if M.member sname sschemas then
235+ Just (Schema oldMorphs) -> do
236+ morph' <- validate morph underlyingRvNames
237+ pure (M.insert sname (Schema (oldMorphs ++ [morph'])) sschemas)
238+evalSchemaExpr (RemoveSubschema sname) _ sschemas = if M.member sname sschemas then
189239 pure (M.delete sname sschemas)
190240 else
191241 Left (SubschemaNameNotInUseError sname)
242+