on master help sign in
fix confusing error message when creating incdep where the expressions do not have equal relation types

resolves #181

commit52a18c6ce2e106d0004126b7eecdb34053473793 authorAgentM <agentm@themactionfaction.com> dateThu 28 Dec 2017, 20:59 (9 years ago) parent14f4a77
5 files changed+23−19
docs/tutd_tutorial.markdown+1−1 src/lib/ProjectM36/Error.hs+1−1 src/lib/ProjectM36/RelationalExpression.hs+18−14 src/lib/ProjectM36/TransactionGraph.hs+2−2 test/Client/Simple.hs+1−1
docs/tutd_tutorial.markdown+1−1
@@ -526,7 +526,7 @@ Foreign keys are constraints which require that certain values appearing in one
526526TutorialD (master/main): foreign key s#_in_sp sp{s#} in s{s#}
527527```
528528
529−This expression ensure that any sp{s#} must also appear as a value in s{s#}.
529+This expression ensure that any sp{s#} must also appear as a value in s{s#}. Note that the sub-expression (on the left of "in") and the super-expression (on the right) must be of the same relation type- the generated relation values' attribute names and types must be equal. Use `rename` to make attribute names identical.
530530
531531#### Functional dependencies
532532
src/lib/ProjectM36/Error.hs+1−1
@@ -24,7 +24,7 @@ data RelationalError = NoSuchAttributeNamesError (S.Set AttributeName)
2424 | CouldNotInferAttributes
2525 | RelVarNotDefinedError RelVarName
2626 | RelVarAlreadyDefinedError RelVarName
27− | RelVarAssignmentTypeMismatchError Attributes Attributes --expected, found
27+ | RelationTypeMismatchError Attributes Attributes --expected, found
2828 | InclusionDependencyCheckError IncDepName
2929 | InclusionDependencyNameInUseError IncDepName
3030 | InclusionDependencyNameNotInUseError IncDepName
src/lib/ProjectM36/RelationalExpression.hs+18−14
@@ -244,8 +244,8 @@ setRelVar relVarName rel = do
244244 potentialContext = currentContext { relationVariables = newRelVars }
245245
246246 case checkConstraints potentialContext of
247− Just err -> pure (Left err)
248− Nothing -> do
247+ Left err -> pure (Left err)
248+ Right _ -> do
249249 putStateContext potentialContext
250250 return (Right ())
251251
@@ -295,7 +295,7 @@ evalDatabaseContextExpr (Assign relVarName expr) = do
295295 if A.attributesEqual expectedAttributes foundAttributes then
296296 setRelVar relVarName rel
297297 else
298− pure (Left (RelVarAssignmentTypeMismatchError expectedAttributes foundAttributes))
298+ pure (Left (RelationTypeMismatchError expectedAttributes foundAttributes))
299299
300300evalDatabaseContextExpr (Insert relVarName relExpr) = do
301301 context <- getStateContext
@@ -359,8 +359,8 @@ evalDatabaseContextExpr (AddInclusionDependency newDepName newDep) = do
359359 else do
360360 let potentialContext = currContext { inclusionDependencies = newDeps }
361361 case checkConstraints potentialContext of
362− Just err -> pure (Left err)
363− Nothing -> do
362+ Left err -> pure (Left err)
363+ Right _ -> do
364364 putStateContext potentialContext
365365 return (Right ())
366366
@@ -574,22 +574,26 @@ updateTupleWithAtomExprs exprMap context tupIn = do
574574 pure (updateTupleWithAtoms (M.fromList atomsAssoc) tupIn)
575575
576576--run verification on all constraints
577−checkConstraints :: DatabaseContext -> Maybe RelationalError
578−checkConstraints context = case failures of
579− [] -> Nothing
580− l:_ -> Just l
577+checkConstraints :: DatabaseContext -> Either RelationalError ()
578+checkConstraints context = do
579+ mapM_ (uncurry checkIncDep) (M.toList deps)
580+ pure ()
581581 where
582− failures = M.elems $ M.mapMaybeWithKey checkIncDep deps
583582 deps = inclusionDependencies context
584− eval expr = runReader (evalRelationalExpr expr) (RelationalExprStateElems context)
583+ eval expr = evalReader (evalRelationalExpr expr)
584+ evalReader f = runReader f (RelationalExprStateElems context)
585585 checkIncDep depName (InclusionDependency subsetExpr supersetExpr) = do
586+ --if both expressions are of a single-attribute (such as with a simple foreign key), the names of the attributes are irrelevant (they need not match) because the expression is unambiguous, but special-casing this to rename the attribute automatically would not be orthogonal behavior and probably cause confusion. Instead, special case the error to make it clear.
587+ typeSub <- evalReader (typeForRelationalExpr subsetExpr)
588+ typeSuper <- evalReader (typeForRelationalExpr supersetExpr)
589+ when (typeSub /= typeSuper) (Left (RelationTypeMismatchError (attributes typeSub) (attributes typeSuper)))
586590 let checkExpr = Equals supersetExpr (Union subsetExpr supersetExpr)
587591 case eval checkExpr of
588− Left err -> Just err
592+ Left err -> Left err
589593 Right resultRel -> if resultRel == relationTrue then
590− Nothing
594+ pure ()
591595 else
592− Just $ InclusionDependencyCheckError depName
596+ Left (InclusionDependencyCheckError depName)
593597
594598-- the type of a relational expression is equal to the relation attribute set returned from executing the relational expression; therefore, the type can be cheaply derived by evaluating a relational expression and ignoring and tuple processing
595599-- furthermore, the type of a relational expression is the resultant header of the evaluated empty-tupled relation
src/lib/ProjectM36/TransactionGraph.hs+2−2
@@ -407,8 +407,8 @@ mergeTransactions stamp newId parentId mergeStrategy (headNameA, headNameB) grap
407407 case createMergeTransaction stamp newId mergeStrategy subGraph' (transA, transB) of
408408 Left err -> Left (MergeTransactionError err)
409409 Right mergedTrans -> case checkConstraints (concreteDatabaseContext mergedTrans) of
410− Just err -> Left err
411− Nothing -> case headNameForTransaction disconParent graph of
410+ Left err -> Left err
411+ Right _ -> case headNameForTransaction disconParent graph of
412412 Nothing -> Left (TransactionIsNotAHeadError parentId)
413413 Just headName -> do
414414 (newTrans, newGraph) <- addTransactionToGraph headName mergedTrans graph
test/Client/Simple.hs+1−1
@@ -55,7 +55,7 @@ testSimpleCommitFailure = TestCase $ do
5555 execute $ Assign "x" (ExistingRelation relationTrue)
5656 --cause error
5757 execute $ Assign "x" (MakeStaticRelation failAttrs emptyTupleSet)
58− let expectedErr = Left (RelError (RelVarAssignmentTypeMismatchError V.empty failAttrs))
58+ let expectedErr = Left (RelError (RelationTypeMismatchError V.empty failAttrs))
5959 assertEqual "dbc error" expectedErr err
6060
6161