packages feed

project-m36 0.4 → 0.5

raw patch · 44 files changed

+505/−169 lines, 44 filesdep +deferred-foldsdep +foldldep ~Win32dep ~distributed-processdep ~distributed-process-async

Dependencies added: deferred-folds, foldl

Dependency ranges changed: Win32, distributed-process, distributed-process-async, megaparsec, network-transport-tcp, stm-containers

Files

Changelog.markdown view
@@ -1,3 +1,11 @@+# 2018-08-10 (v0.5)++* fix critical type bug which allowed unresolved types to be used+* add full support for GHC 8.2 with stack or cabal (delayed for a long time by dependency version boundaries)+* drop support for GHC 7.10+* add support for `with (relexpr as name,...)` syntax for use as tutd macros+* add `NonEmptyList` list data type+ # 2018-06-04 (v0.4)  * add contributed feature to allow users to [create arbitrary relations](https://github.com/agentm/project-m36/blob/master/docs/tutd_tutorial.markdown#arbitrary-relation-variables)
README.markdown view
@@ -86,7 +86,7 @@  ## Development -Project:M36 is developed in Haskell and compiled with GHC 7.10 or GHC 8.0.2 or later.+Project:M36 is developed in Haskell and compiled with GHC 8.0.2 or later.  ## Related Projects 
project-m36.cabal view
@@ -1,5 +1,5 @@ Name: project-m36-Version: 0.4+Version: 0.5 License: PublicDomain Build-Type: Simple Homepage: https://github.com/agentm/project-m36@@ -71,17 +71,20 @@                    ,conduit                    ,resourcet                    ,http-api-data+                   ,semigroups                    -- used for arbitrary tuples                    ,QuickCheck --needed for remote access                    ,distributed-process-client-server >= 0.2.3-                   ,distributed-process >= 0.6.6+                   ,distributed-process >= 0.7.2                    ,distributed-process-extras >= 0.3.2-                   ,distributed-process-async >= 0.2.4-                   ,network-transport-tcp+                   ,distributed-process-async >= 0.2.4.1+                   ,network-transport-tcp >= 0.6.0                    ,network-transport                    ,list-t                    ,stm-containers >= 0.2.15+                   ,foldl+                   ,deferred-folds                    ,optparse-applicative                    ,Glob --used for hashing the transaction graph file to check for differences@@ -137,6 +140,7 @@                      ProjectM36.DataTypes.Either,                      ProjectM36.DataTypes.Maybe,                      ProjectM36.DataTypes.List,+                     ProjectM36.DataTypes.NonEmptyList,                      ProjectM36.DataTypes.Primitive,                      ProjectM36.DataTypes.Interval,                      ProjectM36.DataTypes.ByteString,@@ -158,7 +162,7 @@                      ProjectM36.Arbitrary     GHC-Options: -Wall -rdynamic     if os(windows)-      Build-Depends: Win32 >= 2.3+      Build-Depends: Win32 >= 2.5.4.1       Other-Modules: ProjectM36.Win32Handle     else       C-sources: cbits/DirectoryFsync.c, cbits/darwin_statfs.c@@ -201,13 +205,13 @@                    directory,                    filepath,                    temporary,-                   megaparsec >= 5.2.0 && < 5.4,+                   megaparsec >= 5.2.0 && < 7,                    haskeline,                    random, MonadRandom,                    base64-bytestring,                    optparse-applicative,                    attoparsec,-                   stm-containers,+                   stm-containers >= 1.0.0,                    list-t     Other-Modules: TutorialD.Interpreter,                    TutorialD.Interpreter.Base,@@ -440,7 +444,7 @@     Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics, binary, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, aeson, path-pieces, either, conduit, http-api-data, template-haskell, ghc, ghc-paths, project-m36     Main-Is: examples/CustomTupleable.hs     GHC-Options: -Wall-    + Test-Suite test-scripts     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings@@ -554,4 +558,4 @@     if flag(profiler)       GHC-Prof-Options: -fprof-auto -rtsopts -threaded -Wall   -  +
src/bin/ProjectM36/Server/WebSocket.hs view
@@ -14,7 +14,7 @@ import ProjectM36.Relation.Show.HTML import Data.Aeson import TutorialD.Interpreter-import TutorialD.Interpreter.Base+import TutorialD.Interpreter.Base (TutorialDOperatorResult(..)) import ProjectM36.Client import Control.Exception import Data.Attoparsec.Text
src/bin/ProjectM36/Server/WebSocket/websocket-server.hs view
@@ -1,10 +1,17 @@+{-# LANGUAGE CPP #-} import ProjectM36.Server.WebSocket import ProjectM36.Server.Config import ProjectM36.Server.ParseArgs import ProjectM36.Server import Control.Concurrent import qualified Network.WebSockets as WS++#if MIN_VERSION_network_transport_tcp(0,6,0)                +import Network.Transport.TCP.Internal (decodeEndPointAddress)+#else import Network.Transport.TCP (decodeEndPointAddress)+#endif+ import Control.Exception  main :: IO ()
src/bin/TutorialD/Interpreter.hs view
@@ -24,8 +24,6 @@ import qualified ProjectM36.Client as C import ProjectM36.Relation (attributes) -import Text.Megaparsec-import Text.Megaparsec.Text import System.Console.Haskeline import System.Directory (getHomeDirectory) import qualified Data.Text as T@@ -79,11 +77,11 @@   where     transInfo = either (const "<unknown>") id eHeadName <> "/" <> either (const "<no schema>") id eSchemaName           -parseTutorialD :: T.Text -> Either (ParseError Char Dec) ParsedOperation+parseTutorialD :: T.Text -> Either ParserError ParsedOperation parseTutorialD = parse interpreterParserP ""  --only parse tutoriald which doesn't result in file I/O-safeParseTutorialD :: T.Text -> Either (ParseError Char Dec) ParsedOperation+safeParseTutorialD :: T.Text -> Either ParserError ParsedOperation safeParseTutorialD = parse safeInterpreterParserP ""  data SafeEvaluationFlag = SafeEvaluation | UnsafeEvaluation deriving (Eq)
src/bin/TutorialD/Interpreter/Base.hs view
@@ -1,12 +1,30 @@ {-# LANGUAGE DeriveGeneric, CPP #-}-module TutorialD.Interpreter.Base where+module TutorialD.Interpreter.Base (+  module TutorialD.Interpreter.Base, +  module Text.Megaparsec,+#if MIN_VERSION_megaparsec(6,0,0)  +  module Text.Megaparsec.Char,+  module Control.Applicative+#else+  module Text.Megaparsec.Text+#endif+ )+  where import ProjectM36.Base import ProjectM36.AtomType import ProjectM36.Relation +#if MIN_VERSION_megaparsec(6,0,0)+import Text.Megaparsec.Char+import qualified Text.Megaparsec.Char.Lexer as Lex import Text.Megaparsec+import Data.Void+import Control.Applicative hiding (many, some)+#else import Text.Megaparsec.Text import qualified Text.Megaparsec.Lexer as Lex+#endif+ import Data.Text hiding (count) import System.Random import qualified Data.Text as T@@ -42,16 +60,23 @@   maybe (pure ()) (TIO.putStrLn . pointyString) mPromptLength   TIO.putStr ("ERR:" <> errString) +#if MIN_VERSION_megaparsec(6,0,0)+type Parser = Parsec Void Text+type ParseStr = Text+#else+type ParseStr = String+#endif+ spaceConsumer :: Parser () spaceConsumer = Lex.space (void spaceChar) (Lex.skipLineComment "--") (Lex.skipBlockComment "{-" "-}")    opChar :: Parser Char opChar = oneOf (":!#$%&*+./<=>?\\^|-~" :: String)-- remove "@" so it can be used as attribute marker without spaces -reserved :: String -> Parser ()+reserved :: ParseStr -> Parser () reserved word = try (string word *> notFollowedBy opChar *> spaceConsumer) -reservedOp :: String -> Parser ()+reservedOp :: ParseStr -> Parser () reservedOp op = try (spaceConsumer *> string op *> notFollowedBy opChar *> spaceConsumer)  parens :: Parser a -> Parser a@@ -67,8 +92,12 @@   spaceConsumer   pure (pack (istart:irest)) -symbol :: String -> Parser Text+symbol :: ParseStr -> Parser Text+#if MIN_VERSION_megaparsec(6,0,0)+symbol sym = Lex.symbol spaceConsumer sym+#else symbol sym = pack <$> Lex.symbol spaceConsumer sym+#endif  comma :: Parser Text comma = symbol ","@@ -88,13 +117,12 @@ semi :: Parser Text semi = symbol ";" -{--whiteSpace :: Parser ()-whiteSpace = Token.whiteSpace lexer--}- integer :: Parser Integer+#if MIN_VERSION_megaparsec(6,0,0)+integer = Lex.signed spaceConsumer Lex.decimal+#else integer = Lex.signed spaceConsumer Lex.integer+#endif  float :: Parser Double float = Lex.float@@ -123,12 +151,18 @@  type PromptLength = Int  +#if MIN_VERSION_megaparsec(6,0,0)+type ParserError = ParseError Char Void+#else    +type ParserError = ParseError Char Dec  +#endif+ data TutorialDOperatorResult = QuitResult |                                DisplayResult StringType |                                DisplayIOResult (IO ()) |                                DisplayRelationResult Relation |                                DisplayErrorResult StringType |-                               DisplayParseErrorResult (Maybe PromptLength) (ParseError Char Dec) | -- Int refers to length of prompt text+                               DisplayParseErrorResult (Maybe PromptLength) ParserError | -- PromptLength refers to length of prompt text                                QuietSuccessResult                                deriving (Generic)                                
src/bin/TutorialD/Interpreter/DatabaseContextExpr.hs view
@@ -1,6 +1,4 @@ module TutorialD.Interpreter.DatabaseContextExpr where-import Text.Megaparsec-import Text.Megaparsec.Text import ProjectM36.Base import TutorialD.Interpreter.Base import qualified Data.Text as T@@ -47,8 +45,7 @@     relVarName <- identifier     reservedOp ":="     return relVarName-  expr <- relExprP-  pure $ Assign relVarName expr+  Assign relVarName <$> relExprP    multilineSep :: Parser T.Text   multilineSep = newline >> pure "\n"@@ -61,8 +58,7 @@ insertP = do   reservedOp "insert"   relvar <- identifier-  expr <- relExprP-  pure $ Insert relvar expr+  Insert relvar <$> relExprP  defineP :: Parser DatabaseContextExpr defineP = do@@ -70,8 +66,7 @@     relVarName <- identifier     reservedOp "::"     return relVarName-  attributeSet <- makeAttributeExprsP-  pure $ Define relVarName attributeSet+  Define relVarName <$> makeAttributeExprsP  undefineP :: Parser DatabaseContextExpr undefineP = do@@ -110,8 +105,7 @@ deleteConstraintP :: Parser DatabaseContextExpr   deleteConstraintP = do   reserved "deleteconstraint"-  constraintName <- identifier-  pure $ RemoveInclusionDependency constraintName+  RemoveInclusionDependency <$> identifier    -- key <constraint name> {<uniqueness attributes>} <uniqueness relexpr> keyP :: Parser DatabaseContextExpr  @@ -151,14 +145,12 @@   notName <- identifier   triggerExpr <- relExprP    resultOldExpr <- relExprP-  resultNewExpr <- relExprP-  pure $ AddNotification notName triggerExpr resultOldExpr resultNewExpr+  AddNotification notName triggerExpr resultOldExpr <$> relExprP    removeNotificationP :: Parser DatabaseContextExpr   removeNotificationP = do   reserved "unnotify"-  notName <- identifier-  pure $ RemoveNotification notName+  RemoveNotification <$> identifier  -- | data Hair = Bald | Color Text addTypeConstructorP :: Parser DatabaseContextExpr
src/bin/TutorialD/Interpreter/DatabaseContextIOOperator.hs view
@@ -1,11 +1,8 @@ --compiling the script requires the IO monad because it must load modules from the filesystem, so we create the function and generate the requisite DatabaseExpr here. module TutorialD.Interpreter.DatabaseContextIOOperator where import ProjectM36.Base- import TutorialD.Interpreter.Base import TutorialD.Interpreter.Types-import Text.Megaparsec-import Text.Megaparsec.Text import Data.Text  addAtomFunctionExprP :: Parser DatabaseContextIOExpr@@ -24,13 +21,12 @@   max' <- fromInteger <$> integer   pure $ CreateArbitraryRelation relVarName attrExprs (min',max')   -dbioexprP :: String -> (Text -> [TypeConstructor] -> Text -> DatabaseContextIOExpr) -> Parser DatabaseContextIOExpr+dbioexprP :: ParseStr -> (Text -> [TypeConstructor] -> Text -> DatabaseContextIOExpr) -> Parser DatabaseContextIOExpr dbioexprP res adt = do   reserved res   funcName <- quotedString   funcType <- atomTypeSignatureP-  funcScript <- quotedString-  pure $ adt funcName funcType funcScript+  adt funcName funcType <$> quotedString  atomTypeSignatureP :: Parser [TypeConstructor] atomTypeSignatureP = sepBy typeConstructorP arrow
src/bin/TutorialD/Interpreter/Export/CSV.hs view
@@ -2,10 +2,9 @@ import ProjectM36.Relation.Show.CSV import TutorialD.Interpreter.Export.Base import TutorialD.Interpreter.RelationalExpr-import TutorialD.Interpreter.Base+import TutorialD.Interpreter.Base hiding (try) import ProjectM36.Base import ProjectM36.Error-import Text.Megaparsec.Text import qualified Data.ByteString.Lazy as BS import Control.Exception (try) import qualified Data.Text as T
src/bin/TutorialD/Interpreter/Import/BasicExamples.hs view
@@ -1,10 +1,14 @@+{-# LANGUAGE CPP #-} --includes some hardcoded examples which can be imported even during safe evaluation (no file I/O) module TutorialD.Interpreter.Import.BasicExamples where import ProjectM36.DateExamples import ProjectM36.Base import ProjectM36.DatabaseContext import TutorialD.Interpreter.Base++#if !MIN_VERSION_megaparsec(6,0,0) import Text.Megaparsec.Text+#endif  data ImportBasicExampleOperator = ImportBasicDateExampleOperator                                 deriving (Show)
src/bin/TutorialD/Interpreter/Import/CSV.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} module TutorialD.Interpreter.Import.CSV where import TutorialD.Interpreter.Import.Base import ProjectM36.Base@@ -5,8 +6,7 @@ import ProjectM36.Relation.Parse.CSV hiding (quotedString) import qualified Data.ByteString.Lazy as BS import qualified Data.Text as T-import Text.Megaparsec.Text-import TutorialD.Interpreter.Base+import TutorialD.Interpreter.Base hiding (try) import Control.Exception  importCSVRelation :: RelVarName -> TypeConstructorMapping -> Attributes -> FilePath -> IO (Either RelationalError DatabaseContextExpr)
src/bin/TutorialD/Interpreter/Import/TutorialD.hs view
@@ -1,10 +1,8 @@ module TutorialD.Interpreter.Import.TutorialD where import ProjectM36.Base import TutorialD.Interpreter.Import.Base-import TutorialD.Interpreter.Base+import TutorialD.Interpreter.Base hiding (try) import TutorialD.Interpreter.DatabaseContextExpr-import Text.Megaparsec.Text-import Text.Megaparsec hiding (try) import ProjectM36.Error import qualified ProjectM36.Error as PM36E import qualified Data.Text as T
src/bin/TutorialD/Interpreter/InformationOperator.hs view
@@ -2,7 +2,6 @@ module TutorialD.Interpreter.InformationOperator where import Data.Text import Text.Megaparsec-import Text.Megaparsec.Text import TutorialD.Interpreter.Base -- older versions of stack fail to #if !defined(VERSION_project_m36) 
src/bin/TutorialD/Interpreter/RODatabaseContextOperator.hs view
@@ -4,8 +4,6 @@ import ProjectM36.Error import ProjectM36.InclusionDependency import qualified ProjectM36.Client as C-import Text.Megaparsec-import Text.Megaparsec.Text import TutorialD.Interpreter.Base import TutorialD.Interpreter.RelationalExpr import TutorialD.Interpreter.DatabaseContextExpr
src/bin/TutorialD/Interpreter/RelationalExpr.hs view
@@ -2,7 +2,6 @@ import Text.Megaparsec import Text.Megaparsec.Expr import ProjectM36.Base-import Text.Megaparsec.Text import TutorialD.Interpreter.Base import TutorialD.Interpreter.Types import qualified Data.Text as T@@ -92,8 +91,7 @@ ungroupP :: Parser (RelationalExprBase a -> RelationalExprBase a) ungroupP = do   reservedOp "ungroup"-  rvaAttrName <- identifier-  pure $ Ungroup rvaAttrName+  Ungroup <$> identifier  extendP :: RelationalMarkerExpr a => Parser (RelationalExprBase a -> RelationalExprBase a) extendP = do@@ -130,7 +128,7 @@   ]  relExprP :: RelationalMarkerExpr a => Parser (RelationalExprBase a)-relExprP = makeExprParser relTerm relOperators+relExprP = try withMacroExprP <|> makeExprParser relTerm relOperators  relVarP :: RelationalMarkerExpr a => Parser (RelationalExprBase a) relVarP = RelationVariable <$> identifier <*> parseMarkerP@@ -204,8 +202,7 @@ constructedAtomExprP consume = do   dConsName <- capitalizedIdentifier   dConsArgs <- if consume then sepBy (consumeAtomExprP False) spaceConsumer else pure []-  marker <- parseMarkerP-  pure $ ConstructedAtomExpr dConsName dConsArgs marker+  ConstructedAtomExpr dConsName dConsArgs <$> parseMarkerP    -- used only for primitive type parsing ? atomP :: Parser Atom@@ -237,3 +234,17 @@    relationAtomExprP :: RelationalMarkerExpr a => Parser (AtomExprBase a) relationAtomExprP = RelationAtomExpr <$> makeRelationP++withMacroExprP :: RelationalMarkerExpr a => Parser (RelationalExprBase a)+withMacroExprP = do+  reservedOp "with"+  views <- parens (sepBy1 createViewP comma) +  With views <$> relExprP++createViewP :: RelationalMarkerExpr a => Parser (RelVarName, RelationalExprBase a)+createViewP = do +  name <- identifier+  reservedOp "as"+  expr <- relExprP+  pure (name, expr)+ 
src/bin/TutorialD/Interpreter/SchemaOperator.hs view
@@ -1,7 +1,5 @@ module TutorialD.Interpreter.SchemaOperator where import Text.Megaparsec-import Text.Megaparsec.Text- import ProjectM36.Base import ProjectM36.IsomorphicSchema import ProjectM36.Session
src/bin/TutorialD/Interpreter/TransGraphRelationalOperator.hs view
@@ -9,9 +9,6 @@ import TutorialD.Interpreter.Base import TutorialD.Interpreter.RelationalExpr -import Text.Megaparsec-import Text.Megaparsec.Text- import qualified Data.Text as T  instance RelationalMarkerExpr TransactionIdLookup where
src/bin/TutorialD/Interpreter/TransactionGraphOperator.hs view
@@ -1,8 +1,6 @@ {-# LANGUAGE GADTs #-} module TutorialD.Interpreter.TransactionGraphOperator where import TutorialD.Interpreter.Base-import Text.Megaparsec.Text-import Text.Megaparsec import ProjectM36.TransactionGraph hiding (autoMergeToHead) import ProjectM36.Client import ProjectM36.Base@@ -63,20 +61,15 @@ mergeTransactionStrategyP = (reserved "union" $> UnionMergeStrategy) <|>                             (do                                 reserved "selectedbranch"-                                branch <- identifier-                                pure (SelectedBranchMergeStrategy branch)) <|>+                                SelectedBranchMergeStrategy <$> identifier) <|>                             (do                                 reserved "unionpreferbranch"-                                branch <- identifier-                                pure (UnionPreferMergeStrategy branch))+                                UnionPreferMergeStrategy <$> identifier)    mergeTransactionsP :: Parser TransactionGraphOperator mergeTransactionsP = do   reservedOp ":mergetrans"-  strategy <- mergeTransactionStrategyP-  headA <- identifier-  headB <- identifier-  pure (MergeTransactions strategy headA headB)+  MergeTransactions <$> mergeTransactionStrategyP <*> identifier <*> identifier  transactionGraphOpP :: Parser TransactionGraphOperator transactionGraphOpP = 
src/bin/TutorialD/Interpreter/Types.hs view
@@ -1,7 +1,6 @@ --parse type and data constructors module TutorialD.Interpreter.Types where import ProjectM36.Base-import Text.Megaparsec.Text import Text.Megaparsec import TutorialD.Interpreter.Base @@ -41,7 +40,6 @@  attributeAndTypeNameP :: RelationalMarkerExpr a => Parser (AttributeExprBase a) attributeAndTypeNameP = AttributeAndTypeNameExpr <$> identifier <*> typeConstructorP <*> parseMarkerP-                                -- *Either Int Text*, *Int* typeConstructorP :: Parser TypeConstructor                  
src/bin/benchmark/Handles.hs view
@@ -4,9 +4,8 @@ import ProjectM36.Persist import Options.Applicative import TutorialD.Interpreter-import TutorialD.Interpreter.Base+import TutorialD.Interpreter.Base hiding (Parser, option) import qualified Data.Text as T-import Text.Megaparsec hiding (option) import Data.Monoid import Control.Monad 
src/bin/benchmark/bigrel.hs view
@@ -6,14 +6,14 @@ import ProjectM36.Error import qualified ProjectM36.Attribute as A import qualified Data.Text as T-import ProjectM36.Relation.Show.CSV+--import ProjectM36.Relation.Show.CSV import ProjectM36.Relation.Show.HTML import TutorialD.Interpreter.DatabaseContextExpr (interpretDatabaseContextExpr) import ProjectM36.RelationalExpression-import qualified Data.HashSet as HS-import qualified Data.ByteString.Lazy.Char8 as BS-import qualified Data.IntMap as IM-import qualified Data.Hashable as Hash+--import qualified Data.HashSet as HS+--import qualified Data.ByteString.Lazy.Char8 as BS+--import qualified Data.IntMap as IM+--import qualified Data.Hashable as Hash import qualified Data.Vector as V import Options.Applicative import qualified Data.Map as M@@ -24,10 +24,12 @@ import Data.Text hiding (map) import Data.Monoid +{- dumpcsv :: Relation -> IO () dumpcsv rel = case relationAsCSV rel of   Left err -> hPrint stderr err   Right bsData -> BS.putStrLn bsData+-}  data BigrelArgs = BigrelArgs Int Int Text @@ -67,37 +69,47 @@                      Right context' -> TIO.putStrLn $ relationAsHTML (relationVariables context' M.! "x")                      Left err -> hPrint stderr err -+{- intmapMatrixRun :: IO () intmapMatrixRun = do   let matrix = intmapMatrixRelation 100 100000   print matrix+-}  --compare IntMap speed and size --this is about 3 times faster (9 minutes) for 10x100000 and uses 800 MB+{- intmapMatrixRelation :: Int -> Int -> HS.HashSet (IM.IntMap Atom) intmapMatrixRelation attributeCount tupleCount = HS.fromList $ map mapper [0..tupleCount]   where     mapper tupCount = IM.fromList $ map (\c-> (c, IntAtom (fromIntegral tupCount))) [0..attributeCount]--instance Hash.Hashable (IM.IntMap Atom) where-  hashWithSalt salt tupMap = Hash.hashWithSalt salt (show tupMap)+-}+-- instance Hash.Hashable (IM.IntMap Atom) where+--  hashWithSalt salt tupMap = Hash.hashWithSalt salt (show tupMap) +{- vectorMatrixRun :: IO () vectorMatrixRun = do   let matrix = vectorMatrixRelation 100 100000   print matrix+-}+-- 20 s 90 MBs- a clear win- ideal size is 10 * 100000 * 8 bytes = 80 MB! without IntAtom wrapper+--with IntAtom wrapper: 1m12s 90 MB+{- + -- 20 s 90 MBs- a clear win- ideal size is 10 * 100000 * 8 bytes = 80 MB! without IntAtom wrapper --with IntAtom wrapper: 1m12s 90 MB+{-                    + vectorMatrixRelation :: Int -> Int -> HS.HashSet (V.Vector Atom) vectorMatrixRelation attributeCount tupleCount = HS.fromList $ map mapper [0..tupleCount]   where     mapper tupCount = V.replicate attributeCount (IntAtom (fromIntegral tupCount))-+-} instance Hash.Hashable (V.Vector Atom) where   hashWithSalt salt vec = Hash.hashWithSalt salt (show vec)-+-} -- returns a relation with tupleCount tuples with a set of integer attributes attributesCount long -- this is useful for performance and resource usage testing matrixRelation :: Int -> Int -> Either RelationalError Relation
src/lib/ProjectM36/AtomFunctions/Basic.hs view
@@ -6,6 +6,7 @@ import ProjectM36.DataTypes.Maybe import ProjectM36.DataTypes.Interval import ProjectM36.DataTypes.ByteString+import ProjectM36.DataTypes.NonEmptyList import ProjectM36.AtomFunctions.Primitive import ProjectM36.AtomFunction import ProjectM36.DataTypes.List@@ -19,6 +20,7 @@                                 eitherAtomFunctions,                                 maybeAtomFunctions,                                 listAtomFunctions,+                                nonEmptyListAtomFunctions,                                 bytestringAtomFunctions,                                 intervalAtomFunctions] 
src/lib/ProjectM36/AtomType.hs view
@@ -31,6 +31,7 @@       [dCons] -> Just dCons       _ -> error "More than one data constructor with the same name found"   +{- -- | Scan the atom types and return the resultant ConstructedAtomType or error. -- Used in typeFromAtomExpr to validate argument types. atomTypeForDataConstructorName :: DataConstructorName -> [AtomType] -> TypeConstructorMapping -> Either RelationalError AtomType@@ -38,8 +39,12 @@ atomTypeForDataConstructorName dConsName atomTypesIn tConsList =   case findDataConstructor dConsName tConsList of     Nothing -> Left (NoSuchDataConstructorError dConsName)-    Just (tCons, dCons) -> -      ConstructedAtomType (TCD.name tCons) <$> resolveDataConstructorTypeVars dCons atomTypesIn tConsList+    Just (tCons, dCons) -> do+      dConsVars <- resolveDataConstructorTypeVars dCons atomTypesIn tConsList      +      let tConsVars = M.fromList (map TypeVariableType (TCD.typeVars tCons))+          allVars = M.union dConsVars tConsVars+      ConstructedAtomType (TCD.name tCons) <$> allVars+-}          atomTypeForDataConstructorDefArg :: DataConstructorDefArg -> AtomType -> TypeConstructorMapping ->  Either RelationalError AtomType atomTypeForDataConstructorDefArg (DataConstructorDefTypeConstructorArg tCons) aType tConss = do@@ -49,15 +54,20 @@ atomTypeForDataConstructorDefArg (DataConstructorDefTypeVarNameArg _) aType _ = Right aType --any type is OK          -- | Used to determine if the atom arguments can be used with the data constructor.  --- | This is the entry point for type-checking from RelationalExpression.hs.+-- | This is the entry point for type-checking from RelationalExpression.hs atomTypeForDataConstructor :: TypeConstructorMapping -> DataConstructorName -> [AtomType] -> Either RelationalError AtomType atomTypeForDataConstructor tConss dConsName atomArgTypes =   --lookup the data constructor   case findDataConstructor dConsName tConss of     Nothing -> Left (NoSuchDataConstructorError dConsName)-    Just (tCons, dCons) -> +    Just (tCons, dCons) -> do       --validate that the type constructor arguments are fulfilled in the data constructor-      ConstructedAtomType (TCD.name tCons) <$> resolveDataConstructorTypeVars dCons atomArgTypes tConss+      dConsVars <- resolveDataConstructorTypeVars dCons atomArgTypes tConss+      let tConsVars = M.fromList (map (\v -> (v, TypeVariableType v)) (TCD.typeVars tCons))+          allVars = M.union dConsVars tConsVars+          unresolvedType = ConstructedAtomType (TCD.name tCons) allVars+      --validateAtomType unresolvedType tConss -- do not validate here because the type may not be fully resolved at this point+      pure unresolvedType        -- | Walks the data and type constructors to extract the type variable map. resolveDataConstructorTypeVars :: DataConstructorDef -> [AtomType] -> TypeConstructorMapping -> Either RelationalError TypeVarMap@@ -71,10 +81,11 @@   --if any two maps have the same key and different values, this indicates a type arg mismatch     let typeVarMapFolder valMap acc = case acc of           Left err -> Left err-          Right accMap -> if accMap `M.isSubmapOf` valMap then-                            Right (M.union accMap valMap)-                          else-                            Left (DataConstructorTypeVarsMismatch (DCD.name dCons) accMap valMap)+          Right accMap -> +            case resolveAtomTypesInTypeVarMap valMap accMap of+              Left (TypeConstructorTypeVarMissing _) -> Left (DataConstructorTypeVarsMismatch (DCD.name dCons) accMap valMap)+              Left err -> Left err+              Right ok -> pure ok     case foldr typeVarMapFolder (Right M.empty) maps of       Left err -> Left err       Right typeVarMaps -> pure typeVarMaps@@ -136,8 +147,6 @@       rightSideVars = S.unions (map DCD.typeVars dConsList)       varsDiff = S.difference leftSideVars rightSideVars   mapM_ tell [map DataConstructorUsesUndeclaredTypeVariable (S.toList varsDiff)]-  pure ()-      atomTypeForTypeConstructor :: TypeConstructor -> TypeConstructorMapping -> TypeVarMap -> Either RelationalError AtomType atomTypeForTypeConstructor = atomTypeForTypeConstructorValidate False@@ -180,7 +189,6 @@ isValidAtomTypeForTypeConstructor (RelationAtomType attrs) (RelationAtomTypeConstructor attrExprs) tConsMap = do   evaldAtomTypes <- mapM (\expr -> atomTypeForAttributeExpr expr tConsMap M.empty) attrExprs   mapM_ (uncurry resolveAtomType) (zip (map A.atomType (V.toList attrs)) evaldAtomTypes)-  pure () isValidAtomTypeForTypeConstructor aType tCons _ = Left (AtomTypeTypeConstructorReconciliationError aType (TC.name tCons))  findTypeConstructor :: TypeConstructorName -> TypeConstructorMapping -> Maybe (TypeConstructorDef, [DataConstructorDef])@@ -199,6 +207,12 @@                                                   else                                                     Left (AtomTypeMismatchError typeFromRelation unresolvedType)                                                     +{-+--walk an `AtomType` and apply the type variables in the map+resolveAtomTypeVars :: TypeVarMap -> AtomType -> AtomType   +resolveAtomTypeVars tvMap typ@(TypeVariableType nam) = fromMaybe typ (M.lookup nam tvMap)+resolveAtomTypeVars tvMap (RelationAtomType relAttrs) = +-}                                                     -- this could be optimized to reduce new tuple creation resolveAtomTypesInTypeVarMap :: TypeVarMap -> TypeVarMap -> Either RelationalError TypeVarMap resolveAtomTypesInTypeVarMap resolvedTypeMap unresolvedTypeMap = do@@ -220,24 +234,33 @@             subType@(ConstructedAtomType _ _) -> do               resSubType <- resolveAtomType resType subType               pure (resKey, resSubType)-            otherType -> pure (resKey, otherType)+            _ -> pure (resKey, resType)           Nothing ->             pure (resKey, resType) --swipe the missing type var from the expected map   tVarList <- mapM (uncurry resolveTypePair) (M.toList resolvedTypeMap)   pure (M.fromList tVarList)    -- | See notes at `resolveTypesInTuple`. The typeFromRelation must not include any wildcards.-resolveTypeInAtom :: AtomType -> Atom -> Either RelationalError Atom-resolveTypeInAtom typeFromRelation atomIn@(ConstructedAtom dConsName _ args) = do+resolveTypeInAtom :: AtomType -> Atom -> TypeConstructorMapping -> Either RelationalError Atom+resolveTypeInAtom typeFromRelation@(ConstructedAtomType _ tvMap) atomIn@(ConstructedAtom dConsName _ args) tConss = do   newType <- resolveAtomType typeFromRelation (atomTypeForAtom atomIn)-  pure (ConstructedAtom dConsName newType args)-resolveTypeInAtom _ atom = Right atom+  case findDataConstructor dConsName tConss of+    Nothing -> -- the atom may have been constructed using a constructor function without a public data constructor, no further resolution is possible+      pure atomIn+    Just (_, dConsDef) -> do+      atomArgTypes <- resolvedAtomTypesForDataConstructorDefArgs tConss tvMap dConsDef+      newArgs <- mapM (\(atom, atomTyp) -> resolveTypeInAtom atomTyp atom tConss) (zip args atomArgTypes)+      pure (ConstructedAtom dConsName newType newArgs)+resolveTypeInAtom (RelationAtomType attrs) (RelationAtom (Relation _ tupSet)) tConss = do+  let newTups = mapM (resolveTypesInTuple attrs tConss) (asList tupSet)+  RelationAtom . Relation attrs . RelationTupleSet <$> newTups+resolveTypeInAtom _ atom _ = Right atom    -- | When creating a tuple, the data constructor may not complete the type constructor arguments, so the wildcard "TypeVar x" fills in the type constructor's argument. The tuple type must be resolved before it can be part of a relation, however. -- Example: "Nothing" does not specify the the argument in "Maybe a", so allow delayed resolution in the tuple before it is added to the relation. Note that this resolution could cause a type error. Hardly a Hindley-Milner system.-resolveTypesInTuple :: Attributes -> RelationTuple -> Either RelationalError RelationTuple-resolveTypesInTuple resolvedAttrs (RelationTuple _ tupAtoms) = do-  newAtoms <- mapM (\(atom, resolvedType) -> resolveTypeInAtom resolvedType atom) (zip (V.toList tupAtoms) $ map A.atomType (V.toList resolvedAttrs))+resolveTypesInTuple :: Attributes -> TypeConstructorMapping -> RelationTuple -> Either RelationalError RelationTuple+resolveTypesInTuple resolvedAttrs tConss (RelationTuple _ tupAtoms) = do+  newAtoms <- mapM (\(atom, resolvedType) -> resolveTypeInAtom resolvedType atom tConss) (zip (V.toList tupAtoms) $ map A.atomType (V.toList resolvedAttrs))   Right (RelationTuple resolvedAttrs (V.fromList newAtoms))                             -- | Validate that the type is provided with complete type variables for type constructors.@@ -252,17 +275,29 @@                                           if not (S.null diff) then                                             Left $ TypeConstructorTypeVarsMismatch expectedTyVarNames actualTyVarNames                                           else-                                            Right ()+                                            validateTypeVarMap tVarMap tConss       _ -> Right ()-validateAtomType (RelationAtomType attrs) tConss = do+validateAtomType (RelationAtomType attrs) tConss =   mapM_ (\attr ->          validateAtomType (A.atomType attr) tConss) (V.toList attrs)-  pure () validateAtomType (TypeVariableType x) _ = Left (TypeConstructorTypeVarMissing x)   validateAtomType _ _ = pure () +--ensure that all type vars are fully resolved+validateTypeVarMap :: TypeVarMap -> TypeConstructorMapping -> Either RelationalError ()+validateTypeVarMap tvMap tConss = mapM_ (`validateAtomType` tConss) $ M.elems tvMap+ validateTuple :: RelationTuple -> TypeConstructorMapping -> Either RelationalError ()-validateTuple (RelationTuple _ atoms) tConss = mapM_ (\a -> validateAtomType (atomTypeForAtom a) tConss) atoms+validateTuple (RelationTuple _ atoms) tConss = mapM_ (`validateAtom` tConss) atoms++--ensure that all types are fully resolved+validateAtom :: Atom -> TypeConstructorMapping -> Either RelationalError ()+validateAtom (RelationAtom (Relation _ tupSet)) tConss = mapM_ (`validateTuple` tConss) (asList tupSet)+validateAtom (ConstructedAtom _ dConsType atomArgs) tConss = do+  validateAtomType dConsType tConss+  mapM_ (`validateAtom` tConss) atomArgs+validateAtom _ _ = pure ()+    -- | Determine if two types are equal or compatible (including special handling for TypeVar x). atomTypeVerify :: AtomType -> AtomType -> Either RelationalError AtomType
src/lib/ProjectM36/Atomable.hs view
@@ -1,10 +1,12 @@ {-# LANGUAGE DefaultSignatures, TypeFamilies, TypeOperators, PolyKinds, FlexibleInstances, ScopedTypeVariables, FlexibleContexts #-}+{-# OPTIONS_GHC -fno-warn-orphans #-} module ProjectM36.Atomable where --http://stackoverflow.com/questions/13448361/type-families-with-ghc-generics-or-data-data --instances to marshal Haskell ADTs to ConstructedAtoms and back import ProjectM36.Base import ProjectM36.DataTypes.Primitive import ProjectM36.DataTypes.List+import ProjectM36.DataTypes.NonEmptyList import ProjectM36.DataTypes.Maybe import ProjectM36.DataTypes.Either import GHC.Generics@@ -18,6 +20,7 @@ import Data.Time.Clock import Data.Maybe import Data.Proxy+import qualified Data.List.NonEmpty as NE  --also add haskell scripting atomable support --rename this module to Atomable along with test@@ -52,7 +55,7 @@   toAtomType _ = toAtomTypeG (from (undefined :: a))                          -- | Creates DatabaseContextExpr necessary to load the type constructor and data constructor into the database.-  toAddTypeExpr :: Proxy a -> DatabaseContextExpr+  toAddTypeExpr :: proxy a -> DatabaseContextExpr   default toAddTypeExpr :: (Generic a, AtomableG (Rep a)) => proxy a -> DatabaseContextExpr   toAddTypeExpr _ = toAddTypeExprG (from (undefined :: a)) (toAtomType (Proxy :: Proxy a))   @@ -154,6 +157,18 @@      toAtomType _ = ConstructedAtomType "List" (M.singleton "a" (toAtomType (Proxy :: Proxy a)))   toAddTypeExpr _ = NoOperation++instance Atomable a => Atomable (NE.NonEmpty a) where+  toAtom (x NE.:| []) = ConstructedAtom "NECons" (nonEmptyListAtomType (toAtomType (Proxy :: Proxy a))) [toAtom x]+  toAtom (x NE.:| xs) = ConstructedAtom "NECons" (nonEmptyListAtomType (toAtomType (Proxy :: Proxy a))) (map toAtom (x:xs))+  fromAtom _ = error "improper fromAtom (NonEmptyList a)"++  toAtomType _ = ConstructedAtomType "NonEmptyList" (M.singleton "a" (toAtomType (Proxy :: Proxy a)))+  toAddTypeExpr _ = NoOperation++#if !MIN_VERSION_binary(0,8,4)+instance Binary a => Binary (NE.NonEmpty a)  +#endif  -- Generics class AtomableG g where
src/lib/ProjectM36/Base.hs view
@@ -208,8 +208,10 @@   --- | Returns the true relation iff    Equals (RelationalExprBase a) (RelationalExprBase a) |   NotEquals (RelationalExprBase a) (RelationalExprBase a) |-  Extend (ExtendTupleExprBase a) (RelationalExprBase a)+  Extend (ExtendTupleExprBase a) (RelationalExprBase a) |   --Summarize :: AtomExpr -> AttributeName -> RelationalExpr -> RelationalExpr -> RelationalExpr -- a special case of Extend+  --Evaluate relationalExpr with scoped views+  With [(RelVarName,RelationalExprBase a)] (RelationalExprBase a)   deriving (Show, Eq, Generic, NFData)             instance Binary RelationalExpr
src/lib/ProjectM36/Client.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE DeriveAnyClass, DeriveGeneric, ScopedTypeVariables, BangPatterns #-}+{-# LANGUAGE DeriveAnyClass, DeriveGeneric, ScopedTypeVariables, BangPatterns, PackageImports #-} {-| Module: ProjectM36.Client @@ -128,7 +128,14 @@ import GHC.Conc.Sync  import Network.Transport (Transport(closeTransport))-import Network.Transport.TCP (createTransport, defaultTCPParameters, encodeEndPointAddress)++#if MIN_VERSION_network_transport_tcp(0,6,0)+import Network.Transport.TCP (createTransport, defaultTCPParameters)+import Network.Transport.TCP.Internal (encodeEndPointAddress)+#else+import Network.Transport.TCP (encodeEndPointAddress, createTransport, defaultTCPParameters)+#endif+ import Control.Distributed.Process.Node (newLocalNode, initRemoteTable, runProcess, LocalNode, forkProcess, closeLocalNode) import Control.Distributed.Process.Extras.Internal.Types (whereisRemote) import Control.Distributed.Process.ManagedProcess.Client (call, safeCall)@@ -140,12 +147,17 @@ import Control.Concurrent.MVar import qualified Data.Map as M import Control.Distributed.Process.Serializable (Serializable)-import qualified STMContainers.Map as STMMap-import qualified STMContainers.Set as STMSet+#if MIN_VERSION_stm_containers(1,0,0)+import qualified StmContainers.Map as StmMap+import qualified StmContainers.Set as StmSet+#else+import qualified STMContainers.Map as StmMap+import qualified STMContainers.Set as StmSet+#endif import qualified ProjectM36.Session as Sess import ProjectM36.Session import ProjectM36.Sessions-import ListT+import "list-t" ListT import Data.Binary (Binary) import GHC.Generics (Generic) import Control.DeepSeq (force)@@ -217,7 +229,7 @@ defaultRemoteConnectionInfo = RemoteProcessConnectionInfo defaultDatabaseName (createNodeId "127.0.0.1" defaultServerPort) emptyNotificationCallback   -- | The 'Connection' represents either local or remote access to a database. All operations flow through the connection.-type ClientNodes = STMSet.Set ProcessId+type ClientNodes = StmSet.Set ProcessId  -- internal structure specific to in-process connections data InProcessConnectionConf = InProcessConnectionConf {@@ -252,7 +264,11 @@  createLocalNode :: IO (LocalNode, Transport) createLocalNode = do+#if MIN_VERSION_network_transport_tcp(0,6,0)  +  eLocalTransport <- createTransport "127.0.0.1" "0" (\sn -> ("127.0.0.1", sn)) defaultTCPParameters+#else   eLocalTransport <- createTransport "127.0.0.1" "0" defaultTCPParameters+#endif   case eLocalTransport of     Left err -> error ("failed to create transport: " ++ show err)     Right localTransport -> do@@ -296,8 +312,8 @@     --create date examples graph for now- probably should be empty context in the future     NoPersistence -> do         graphTvar <- newTVarIO freshGraph-        clientNodes <- STMSet.newIO-        sessions <- STMMap.newIO+        clientNodes <- StmSet.newIO+        sessions <- StmMap.newIO         (localNode, transport) <- createLocalNode         notificationPid <- startNotificationListener localNode notificationCallback         mScriptSession <- createScriptSession ghcPkgPaths@@ -353,8 +369,8 @@         Left err' -> return $ Left (SetupDatabaseDirectoryError err')         Right graph' -> do           tvarGraph <- newTVarIO graph'-          sessions <- STMMap.newIO-          clientNodes <- STMSet.newIO+          sessions <- StmMap.newIO+          clientNodes <- StmSet.newIO           (localNode, transport) <- createLocalNode           lockMVar <- newMVar digest           let conn = InProcessConnection InProcessConnectionConf {@@ -388,11 +404,11 @@         Left err -> pure (Left err)         Right transaction -> do             let freshDiscon = DisconnectedTransaction commitId (Trans.schemas transaction) False-            keyDuplication <- STMMap.lookup newSessionId sessions+            keyDuplication <- StmMap.lookup newSessionId sessions             case keyDuplication of                 Just _ -> pure $ Left (SessionIdInUseError newSessionId)                 Nothing -> do-                   STMMap.insert (Session freshDiscon defaultSchemaName) newSessionId sessions+                   StmMap.insert (Session freshDiscon defaultSchemaName) newSessionId sessions                    pure $ Right newSessionId createSessionAtCommit_ _ _ (RemoteProcessConnection _) = error "createSessionAtCommit_ called on remote connection"   @@ -411,12 +427,12 @@ -- | Used internally for server connections to keep track of remote nodes for the purpose of sending notifications later. addClientNode :: Connection -> ProcessId -> IO () addClientNode (RemoteProcessConnection _) _ = error "addClientNode called on remote connection"-addClientNode (InProcessConnection conf) newProcessId = atomically (STMSet.insert newProcessId (ipClientNodes conf))+addClientNode (InProcessConnection conf) newProcessId = atomically (StmSet.insert newProcessId (ipClientNodes conf))  -- | Discards a session, eliminating any uncommitted changes present in the session. closeSession :: SessionId -> Connection -> IO () closeSession sessionId (InProcessConnection conf) = -    atomically $ STMMap.delete sessionId (ipSessions conf)+    atomically $ StmMap.delete sessionId (ipSessions conf) closeSession sessionId conn@(RemoteProcessConnection _) = remoteCall conn (CloseSession sessionId)         -- | 'close' cleans up the database access connection and closes any relevant sockets.@@ -424,7 +440,11 @@ close (InProcessConnection conf) = do   atomically $ do     let sessions = ipSessions conf-    STMMap.deleteAll sessions+#if MIN_VERSION_stm_containers(1,0,0)        +    StmMap.reset sessions+#else+    StmMap.deleteAll sessions+#endif     pure ()   closeLocalNode (ipLocalNode conf)   closeTransport (ipTransport conf)@@ -484,7 +504,7 @@  sessionForSessionId :: SessionId -> Sessions -> STM (Either RelationalError Session) sessionForSessionId sessionId sessions = -  maybe (Left $ NoSuchSessionError sessionId) Right <$> STMMap.lookup sessionId sessions+  maybe (Left $ NoSuchSessionError sessionId) Right <$> StmMap.lookup sessionId sessions    schemaForSessionId :: Session -> STM (Either RelationalError Schema)   schemaForSessionId session = do@@ -526,7 +546,7 @@     Left err -> pure (Left err)     Right session -> case Sess.setSchemaName sname session of       Left err -> pure (Left err)-      Right newSession -> STMMap.insert newSession sessionId sessions >> pure (Right ())+      Right newSession -> StmMap.insert newSession sessionId sessions >> pure (Right ()) setCurrentSchemaName sessionId conn@(RemoteProcessConnection _) sname = remoteCall conn (ExecuteSetCurrentSchema sessionId sname)  -- | Execute a relational expression in the context of the session and connection. Relational expressions are queries and therefore cannot alter the database.@@ -579,7 +599,7 @@                 newSubschemas = Schema.processDatabaseContextExprSchemasUpdate (Sess.subschemas session) expr                 newSchemas = Schemas context' newSubschemas                 newSession = Session newDiscon (Sess.schemaName session)-            STMMap.insert newSession sessionId sessions+            StmMap.insert newSession sessionId sessions             pure (Right ()) executeDatabaseContextExpr sessionId conn@(RemoteProcessConnection _) dbExpr = remoteCall conn (ExecuteDatabaseContextExpr sessionId dbExpr) @@ -629,7 +649,7 @@           let newDiscon = DisconnectedTransaction (Sess.parentId session) newSchemas True               newSchemas = Schemas context' (Sess.subschemas session)               newSession = Session newDiscon (Sess.schemaName session)-          atomically $ STMMap.insert newSession sessionId sessions+          atomically $ StmMap.insert newSession sessionId sessions           pure (Right ()) executeDatabaseContextIOExpr sessionId conn@(RemoteProcessConnection _) dbExpr = remoteCall conn (ExecuteDatabaseContextIOExpr sessionId dbExpr)          @@ -740,7 +760,7 @@                                Left err -> pure $ Left err                                Right previousTrans -> do                                  (evaldNots, nodes) <- executeCommitExprSTM_ (Trans.concreteDatabaseContext previousTrans) (Sess.concreteDatabaseContext session) clientNodes-                                 nodesToNotify <- toList (STMSet.stream nodes)+                                 nodesToNotify <- toList (StmSet.stream nodes)                                  pure $ Right (evaldNots, nodesToNotify, newGraph)                              else                               pure $ Right (M.empty, [], newGraph)@@ -782,7 +802,7 @@           let discon = Sess.disconnectedTransaction session                newSchemas = Schemas newContext newSubschemas               newSession = Session (DisconnectedTransaction (Discon.parentId discon) newSchemas True) (Sess.schemaName session)-          STMMap.insert newSession sessionId sessions+          StmMap.insert newSession sessionId sessions           pure (Right ()) executeSchemaExpr sessionId conn@(RemoteProcessConnection _) schemaExpr = remoteCall conn (ExecuteSchemaExpr sessionId schemaExpr)           @@ -1003,14 +1023,14 @@  --used in tests only transactionGraph_ :: Connection -> IO TransactionGraph-transactionGraph_ (InProcessConnection conf) = atomically $ readTVar (ipTransactionGraph conf)+transactionGraph_ (InProcessConnection conf) = readTVarIO (ipTransactionGraph conf) transactionGraph_ _ = error "remote connection used"  --used in tests only disconnectedTransaction_ :: SessionId -> Connection -> IO DisconnectedTransaction disconnectedTransaction_ sessionId (InProcessConnection conf) = do   let sessions = ipSessions conf-  mSession <- atomically $ STMMap.lookup sessionId sessions+  mSession <- atomically $ StmMap.lookup sessionId sessions   case mSession of     Nothing -> error "No such session"     Just (Sess.Session discon _) -> pure discon@@ -1068,13 +1088,13 @@               Right (discon', graph', transactionIdsToPersist) -> do                 writeTVar graphTvar graph'                 let newSession = Session discon' (Sess.schemaName session)-                STMMap.insert newSession sessionId sessions+                StmMap.insert newSession sessionId sessions                 case transactionForId (Sess.parentId session) oldGraph of                   Left err -> pure $ Left err                   Right previousTrans ->                     if not (Prelude.null transactionIdsToPersist) then do                       (evaldNots, nodes) <- executeCommitExprSTM_ (Trans.concreteDatabaseContext previousTrans) (Sess.concreteDatabaseContext session) clientNodes-                      nodesToNotify <- toList (STMSet.stream nodes)+                      nodesToNotify <- stmSetToList nodes                       pure $ Right (evaldNots, nodesToNotify, graph', transactionIdsToPersist)                     else pure (Right (M.empty, [], graph', [])) @@ -1091,7 +1111,7 @@ writeDisconAndGraph_ graphTvar sessionId session sessions discon graph = do   writeTVar graphTvar graph   let newSession = Session discon (Sess.schemaName session)-  STMMap.insert newSession sessionId sessions+  StmMap.insert newSession sessionId sessions -}  -- | Runs an IO monad, commits the result when the monad returns no errors, otherwise, rolls back the changes and the error.
src/lib/ProjectM36/DataTypes/Basic.hs view
@@ -4,6 +4,7 @@ import ProjectM36.DataTypes.Either import ProjectM36.DataTypes.Maybe import ProjectM36.DataTypes.List+import ProjectM36.DataTypes.NonEmptyList import ProjectM36.DataTypes.Interval import ProjectM36.Base @@ -12,6 +13,7 @@                               maybeTypeConstructorMapping ++                                eitherTypeConstructorMapping ++                                listTypeConstructorMapping +++                              nonEmptyListTypeConstructorMapping ++                               intervalTypeConstructorMapping                                
+ src/lib/ProjectM36/DataTypes/NonEmptyList.hs view
@@ -0,0 +1,53 @@+module ProjectM36.DataTypes.NonEmptyList where+import ProjectM36.Base+import qualified Data.Map as M+import qualified Data.HashSet as HS+import ProjectM36.AtomFunctionError+import ProjectM36.DataTypes.List++nonEmptyListAtomType :: AtomType -> AtomType+nonEmptyListAtomType arg = ConstructedAtomType "NonEmptyList" (M.singleton "a" arg)++-- data NonEmptyList = NECons a (Cons a)+nonEmptyListTypeConstructorMapping :: TypeConstructorMapping+nonEmptyListTypeConstructorMapping = [(ADTypeConstructorDef "NonEmptyList" ["a"],+                           [DataConstructorDef "NECons" [DataConstructorDefTypeVarNameArg "a",+                            DataConstructorDefTypeConstructorArg (ADTypeConstructor "List" [TypeVariable "a"])]])]+                         +nonEmptyListLength :: Atom -> Either AtomFunctionError Int                         +nonEmptyListLength (ConstructedAtom "NECons" _ (_:nextCons:_)) = do+  c <- listLength nextCons+  pure (c + 1)+nonEmptyListLength (ConstructedAtom "NECons" _ _) = pure 1+nonEmptyListLength _ = Left AtomFunctionTypeMismatchError++nonEmptyListHead :: Atom -> Either AtomFunctionError Atom+nonEmptyListHead (ConstructedAtom "NECons" _ (val:_)) = pure val+nonEmptyListHead _ = Left AtomFunctionTypeMismatchError++{-+listMaybeHead :: Atom -> Either AtomFunctionError Atom+listMaybeHead (ConstructedAtom "Cons" _ (val:_)) = pure (ConstructedAtom "Just" aType [val])+  where+    aType = maybeAtomType (atomTypeForAtom val)+listMaybeHead (ConstructedAtom "Empty" (ConstructedAtomType _ tvMap) _) =+  case M.lookup "a" tvMap of+    Nothing -> Left AtomFunctionTypeMismatchError+    Just aType -> pure (ConstructedAtom "Nothing" aType [])+listMaybeHead _ = Left AtomFunctionTypeMismatchError+-}++nonEmptyListAtomFunctions :: AtomFunctions+nonEmptyListAtomFunctions = HS.fromList [+  AtomFunction {+     atomFuncName = "nonEmptyListLength",+     atomFuncType = [nonEmptyListAtomType (TypeVariableType "a"), IntAtomType],+     atomFuncBody = AtomFunctionBody Nothing (\(nonEmptyListAtom:_) ->+                                                 IntAtom . fromIntegral <$> nonEmptyListLength nonEmptyListAtom)+     },+  AtomFunction {+    atomFuncName = "nonEmptyListHead",+    atomFuncType = [nonEmptyListAtomType (TypeVariableType "a"), TypeVariableType "a"],+    atomFuncBody = AtomFunctionBody Nothing (\(nonEmptyListAtom:_) -> nonEmptyListHead nonEmptyListAtom)+    }+  ]
src/lib/ProjectM36/DataTypes/Primitive.hs view
@@ -27,6 +27,9 @@ dayTypeConstructor :: TypeConstructor dayTypeConstructor = PrimitiveTypeConstructor "Day" DayAtomType +dateTimeTypeConstructor :: TypeConstructor+dateTimeTypeConstructor = PrimitiveTypeConstructor "DateTime" DayAtomType+ -- | Return the type of an 'Atom'. atomTypeForAtom :: Atom -> AtomType atomTypeForAtom (IntAtom _) = IntAtomType
src/lib/ProjectM36/RelationalExpression.hs view
@@ -214,6 +214,24 @@       Left err -> return $ Left err       Right relB -> return $ Right $ if relA == relB then relationTrue else relationFalse +evalRelationalExpr (With views mainExpr) = do+  rstate <- ask+  +  let addScopedView ctx (vname,vexpr) = if vname `M.member` relationVariables ctx then+                                          Left (RelVarAlreadyDefinedError vname)+                                        else+                                          case runState (evalDatabaseContextExpr (Assign vname vexpr)) (freshDatabaseState ctx) of+                                            (Left err,_) -> Left err+                                            (Right (), (ctx',_,_)) -> Right ctx'++  case foldM addScopedView (stateElemsContext rstate) views of+       Left err -> return $ Left err+       Right ctx'' -> do +         let evalMainExpr expr = runReader (evalRelationalExpr expr) (RelationalExprStateElems ctx'')+         case evalMainExpr mainExpr of+              Left err -> return $ Left err+              Right rel -> return $ Right rel + --warning: copy-pasta from above- refactor evalRelationalExpr (NotEquals relExprA relExprB) = do   evaldA <- evalRelationalExpr relExprA@@ -616,9 +634,8 @@  --run verification on all constraints checkConstraints :: DatabaseContext -> Either RelationalError ()-checkConstraints context = do+checkConstraints context =   mapM_ (uncurry checkIncDep) (M.toList deps) -  pure ()   where     deps = inclusionDependencies context     eval expr = evalReader (evalRelationalExpr expr)@@ -850,7 +867,7 @@ -- grab the type of the data constructor, then validate that the args match the expected types typeFromAtomExpr attrs (ConstructedAtomExpr dConsName dConsArgs _) =    runExceptT $ do-    argsTypes <- mapM (liftE . typeFromAtomExpr attrs) dConsArgs  +    argsTypes <- mapM (liftE . typeFromAtomExpr attrs) dConsArgs      context <- fmap stateElemsContext (lift ask)     either throwE pure (atomTypeForDataConstructor (typeConstructorMapping context) dConsName argsTypes) @@ -902,24 +919,31 @@ evalAttrExpr _ (NakedAttributeExpr attr) = Right attr    evalTupleExpr :: Maybe Attributes -> TupleExpr -> RelationalExprState (Either RelationalError RelationTuple)-evalTupleExpr attrs (TupleExpr tupMap) = do+evalTupleExpr mAttrs (TupleExpr tupMap) = do   context <- fmap stateElemsContext ask   runExceptT $ do   -- it's not possible for AtomExprs in tuple constructors to reference other Attributes' atoms due to the necessary order-of-operations (need a tuple to pass to evalAtomExpr)- it may be possible with some refactoring of type usage or delayed evaluation- needs more thought, but not a priority   -- I could adjust this logic so that when the attributes are not specified (Nothing), then I can attempt to extract the attributes from the tuple- the type resolution will blow up if an ambiguous data constructor is used (Left 4) and this should allow simple cases to "relation{tuple{a 4}}" to be processed+    let attrs = fromMaybe A.emptyAttributes mAttrs     attrAtoms <- mapM (\(attrName, aExpr) -> do-                          newAtomType <- liftE (typeFromAtomExpr A.emptyAttributes aExpr)+                          --provided when the relation header is available+                          let eExpectedAtomType = A.atomTypeForAttributeName attrName attrs+                          unresolvedType <- liftE (typeFromAtomExpr attrs aExpr)+                          resolvedType <- case eExpectedAtomType of+                            Left _ -> pure unresolvedType+                            Right typeHint -> either throwE pure (resolveAtomType typeHint unresolvedType)+                          --resolve atom typevars based on resolvedType?                           newAtom <- liftE (evalAtomExpr emptyTuple aExpr)-                          pure (attrName, newAtom, newAtomType)+                          pure (attrName, newAtom, resolvedType)                       ) (M.toList tupMap)     let tupAttrs = A.attributesFromList $ map (\(attrName, _, aType) -> Attribute attrName aType) attrAtoms         atoms = V.fromList $ map (\(_, atom, _) -> atom) attrAtoms         tup = mkRelationTuple tupAttrs atoms         tConss = typeConstructorMapping context-        finalAttrs = fromMaybe tupAttrs attrs+        finalAttrs = fromMaybe tupAttrs mAttrs     --verify that the attributes match     when (A.attributeNameSet finalAttrs /= A.attributeNameSet tupAttrs) $ throwE (TupleAttributeTypeMismatchError tupAttrs)-    tup' <- either throwE pure (resolveTypesInTuple finalAttrs (reorderTuple finalAttrs tup))+    tup' <- either throwE pure (resolveTypesInTuple finalAttrs tConss (reorderTuple finalAttrs tup))     _ <- either throwE pure (validateTuple tup' tConss)     pure tup' 
src/lib/ProjectM36/ScriptSession.hs view
@@ -22,12 +22,20 @@ #else import ObjLink #endif+#if __GLASGOW_HASKELL__ >= 802+import BasicTypes+#endif import DynFlags import Panic import Outputable --hiding ((<>)) import PprTyThing import Unsafe.Coerce+#if __GLASGOW_HASKELL__ >= 802 import Type+#elif __GLASGOW_HASKELL__ >= 710+import Type hiding (pprTyThing)  +#else+#endif  import GHC.Exts (addrToAny#) import GHC.Ptr (Ptr(..))@@ -75,7 +83,12 @@                            trustFlags = map TrustPackage required_packages, #endif                                                                    packageFlags = packageFlags dflags ++ packages,+#if __GLASGOW_HASKELL__ >= 802+                           packageDBFlags = map PackageDB localPkgPaths+#else                            extraPkgConfs = const (localPkgPaths ++ [UserPkgConf, GlobalPkgConf])+#endif+                          }         applyGopts flags = foldl gopt_set flags gopts         applyXopts flags = foldl xopt_set flags xopts@@ -107,7 +120,11 @@   --liftIO $ traceShowM (showSDoc dflags' (ppr packages))     _ <- setSessionDynFlags dflags'     let safeImportDecl mn mQual = ImportDecl {+#if __GLASGOW_HASKELL__ >= 802          +          ideclSourceSrc = NoSourceText,+#else           ideclSourceSrc = Nothing,+#endif           ideclName      = noLoc mn,           ideclPkgQual   = Nothing,           ideclSource    = False,@@ -129,7 +146,12 @@           "ProjectM36.DatabaseContextFunctionError",           "ProjectM36.DatabaseContextFunctionUtils",           "ProjectM36.RelationalExpression"]-        qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl (mkModuleName modn) (Just (mkModuleName qualNam))) [+#if __GLASGOW_HASKELL__ >= 802+        mkModName = noLoc . mkModuleName+#else+        mkModName = mkModuleName+#endif +        qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl (mkModuleName modn) (Just (mkModName qualNam))) [           ("Data.Text", "T")           ]     setContext (unqualifiedModules ++ qualifiedModules)@@ -177,7 +199,11 @@ typeCheckScript expectedType inp = do   dflags <- getSessionDynFlags     --catch exception for SyntaxError+#if __GLASGOW_HASKELL__ >= 802+  funcType <- GHC.exprType TM_Inst (unpack inp)    +#else       funcType <- GHC.exprType (unpack inp)+#endif   --liftIO $ putStrLn $ showType dflags expectedType ++ ":::" ++ showType dflags funcType    if eqType funcType expectedType then     pure Nothing@@ -197,7 +223,11 @@  loadFunction :: ModName -> FuncName -> FilePath -> IO (Either LoadSymbolError a) loadFunction modName funcName objPath = do+#if __GLASGOW_HASKELL__ >= 802  +  initObjLinker RetainCAFs+#else   initObjLinker+#endif   loadObj objPath   _ <- resolveObjs   ptr <- lookupSymbol (mangleSymbol Nothing modName funcName)
src/lib/ProjectM36/Server.hs view
@@ -116,7 +116,11 @@         Right conn -> do           let hostname = bindHost daemonConfig               port = bindPort daemonConfig+#if MIN_VERSION_network_transport_tcp(0,6,0)                +          etransport <- createTransport hostname (show port) (\nam -> (hostname, nam)) defaultTCPParameters              +#else                                   etransport <- createTransport hostname (show port) defaultTCPParameters+#endif           case etransport of             Left err -> error ("failed to create transport: " ++ show err)             Right transport -> do@@ -132,4 +136,3 @@                     serve (conn, databaseName daemonConfig, mAddressMVar, address endpoint) initServer (serverDefinition testBool reqTimeout)                   liftIO $ putStrLn "serve returned"                   pure True-  
src/lib/ProjectM36/Sessions.hs view
@@ -1,18 +1,39 @@+{-# LANGUAGE PackageImports #-} module ProjectM36.Sessions where import Control.Concurrent.STM-import qualified STMContainers.Map as STMMap-import ListT+#if MIN_VERSION_stm_containers(1,0,0)+import qualified StmContainers.Map as StmMap+import qualified StmContainers.Set as StmSet+#else+import qualified STMContainers.Map as StmMap+import qualified STMContainers.Set as StmSet+#endif +import "list-t" ListT import ProjectM36.Attribute import ProjectM36.Base import ProjectM36.Session import ProjectM36.Relation import ProjectM36.Error import qualified Data.UUID as U+import qualified Control.Foldl as Foldl+import qualified DeferredFolds.UnfoldM as UnfoldM -type Sessions = STMMap.Map SessionId Session+type Sessions = StmMap.Map SessionId Session -stmMapToList :: STMMap.Map k v -> STM [(k, v)]-stmMapToList = ListT.fold (\l -> return . (:l)) [] . STMMap.stream+--from https://github.com/nikita-volkov/stm-containers/blob/master/test/Main/MapTests.hs+stmMapToList :: StmMap.Map k v -> STM [(k, v)]+#if MIN_VERSION_stm_containers(1,0,0)+stmMapToList = UnfoldM.foldM (Foldl.generalize Foldl.list) . StmMap.unfoldM+#else+stmMapToList = ListT.fold (\l -> return . (:l)) [] . StmMap.stream+#endif++stmSetToList :: StmSet.Set v -> STM [v]+#if MIN_VERSION_stm_containers(1,0,0)+stmSetToList = UnfoldM.foldM (Foldl.generalize Foldl.list) . StmSet.unfoldM+#else+stmSetToList = ListT.fold (\l -> return . (:l)) [] . StmSet.stream+#endif  uuidAtom :: U.UUID -> Atom uuidAtom = TextAtom . U.toText
src/lib/ProjectM36/StaticOptimizer.hs view
@@ -134,6 +134,8 @@    applyStaticRelationalOptimization e@(Extend _ _) = pure $ Right e   +applyStaticRelationalOptimization e@(With _ _) = pure $ Right e  + applyStaticDatabaseOptimization :: DatabaseContextExpr -> DatabaseState (Either RelationalError DatabaseContextExpr) applyStaticDatabaseOptimization x@NoOperation = pure $ Right x applyStaticDatabaseOptimization x@(Define _ _) = pure $ Right x@@ -378,6 +380,7 @@     MakeStaticRelation _ _ -> expr     ExistingRelation _ -> expr     RelationVariable _ _ -> expr+    With _ _ -> expr     Project attrs subexpr ->        Project attrs (applyStaticRestrictionCollapse subexpr)     Union sub1 sub2 ->@@ -420,6 +423,7 @@   MakeStaticRelation _ _ -> expr   ExistingRelation _ -> expr   RelationVariable _ _ -> expr+  With _ _ -> expr   Project _ _ -> expr   --this transformation cannot be inverted because the projection attributes might not exist in the inverted version   Restrict restrictAttrs (Project projAttrs subexpr) -> 
src/lib/ProjectM36/TransGraphRelationalExpression.hs view
@@ -97,6 +97,13 @@   extendExpr' <- evalTransGraphExtendTupleExpr extendExpr graph   expr' <- evalTransGraphRelationalExpr expr graph   pure (Extend extendExpr' expr')+evalTransGraphRelationalExpr (With views expr) graph = do+  evaldViews <- mapM (\(vname, vexpr) -> do+                         vexpr' <- evalTransGraphRelationalExpr vexpr graph+                         pure (vname, vexpr')+                     ) views+  expr' <- evalTransGraphRelationalExpr expr graph+  pure (With evaldViews expr')    evalTransGraphTupleExpr :: TransactionGraph -> TransGraphTupleExpr -> Either RelationalError TupleExpr evalTransGraphTupleExpr graph (TupleExpr attrMap) = do
src/lib/ProjectM36/Transaction/Persist.hs view
@@ -95,7 +95,6 @@     B.encodeFile (transactionInfoPath tempTransDir) (transactionInfo trans)     --move the temp directory to final location     renameSync sync tempTransDir finalTransDir-  pure ()    writeRelVar :: DiskSync -> FilePath -> (RelVarName, Relation) -> IO () writeRelVar sync transDir (relvarName, rel) = do
src/lib/ProjectM36/Win32Handle.hs view
@@ -53,5 +53,8 @@         -- Do what the user originally wanted         action windows_handle +#if MIN_VERSION_Win32(2,5,1)+#else withStablePtr :: a -> (StablePtr a -> IO b) -> IO b withStablePtr value = bracket (newStablePtr value) freeStablePtr+#endif
test/Relation/Atomable.hs view
@@ -31,6 +31,9 @@ data TestListT = TestListC [Integer]               deriving (Show, Generic, Eq, Binary, NFData, Atomable)                        +data TestNonEmptyT = TestNonEmptyC [Integer]+              deriving (Show, Generic, Eq, Binary, NFData, Atomable)+ data Test5T = Test5C {   con1 :: Integer,   con2 :: Integer@@ -48,8 +51,9 @@   if errors tcounts + failures tcounts > 0 then exitFailure else exitSuccess  testList :: Test-testList = TestList [testHaskell2DB, testADT1, testADT2, testADT3, testADT4, testADT5, testBasicMarshaling, testListInstance, testADT6Maybe, testADT7Either]+testList = TestList [testHaskell2DB, testADT1, testADT2, testADT3, testADT4, testADT5, testBasicMarshaling, testListInstance, testNonEmptyInstance, testADT6Maybe, testADT7Either] + -- test some basic data types like int, day, etc. testBasicMarshaling :: Test testBasicMarshaling = TestCase $ do@@ -132,3 +136,8 @@ testListInstance = TestCase $ do   let example = TestListC [3,4,5]   assertEqual "List instance" example (fromAtom (toAtom example))++testNonEmptyInstance :: Test+testNonEmptyInstance = TestCase $ do+  let example = TestNonEmptyC [3,4,5]+  assertEqual "NonEmpty instance" example (fromAtom (toAtom example))
test/Server/Main.hs view
@@ -17,7 +17,13 @@  import Control.Concurrent import Network.Transport (EndPointAddress)++#if MIN_VERSION_network_transport_tcp(0,6,0)                +import Network.Transport.TCP.Internal (encodeEndPointAddress, decodeEndPointAddress)+#else import Network.Transport.TCP (encodeEndPointAddress, decodeEndPointAddress)+#endif+ import Data.Either (isRight) import Control.Exception import System.IO.Temp
test/Server/WebSocket.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP #-} -- test the websocket server import Test.HUnit import qualified Network.WebSockets as WS@@ -17,7 +18,12 @@ import qualified Data.Map as M import qualified Data.ByteString.Lazy as BS import ProjectM36.Relation+#if MIN_VERSION_network_transport_tcp(0,6,0)                +import Network.Transport.TCP.Internal (decodeEndPointAddress)+#else import Network.Transport.TCP (decodeEndPointAddress)+#endif+  --start the websocket server -- run some tutoriald against it
test/TutorialD/Interpreter.hs view
@@ -11,6 +11,8 @@ import ProjectM36.AtomFunctions.Primitive import ProjectM36.DataTypes.Either import ProjectM36.DataTypes.Interval+import ProjectM36.DataTypes.NonEmptyList+import ProjectM36.DataTypes.List import ProjectM36.DateExamples import ProjectM36.Base hiding (Finite) import ProjectM36.TransactionGraph@@ -67,7 +69,10 @@       testAssignWithTypeVar,       testDefineWithTypeVar,       testIntervalType,-      testArbitraryRelation+      testArbitraryRelation,+      testNonEmptyListType,+      testUnresolvedAtomTypes,+      testWithClause       ]     simpleRelTests = [("x:=true", Right relationTrue),                       ("x:=false", Right relationFalse),@@ -160,7 +165,7 @@                            --test Maybe Integer                            ("x:=relation{tuple{a Just 3}}", mkRelationFromList simpleMaybeIntAttributes [[ConstructedAtom "Just" maybeIntegerAtomType [IntegerAtom 3]]]),                            --test Either Integer Text-                           ("x:=relation{tuple{a Left 3}}",  Left (TypeConstructorTypeVarsMismatch (S.fromList ["a","b"]) (S.fromList ["a"]))), -- Left 3, alone is not enough information to imply the type+                           ("x:=relation{tuple{a Left 3}}",  Left (TypeConstructorTypeVarMissing "b")), -- Left 3, alone is not enough information to imply the type                            ("x:=relation{a Either Integer Text}{tuple{a Left 3}}", mkRelationFromList simpleEitherIntTextAttributes [[ConstructedAtom "Left" (eitherAtomType IntegerAtomType TextAtomType) [IntegerAtom 3]]]),                            --test datetime constructor                            ("x:=relation{tuple{a dateTimeFromEpochSeconds(1495199790)}}", mkRelationFromList (A.attributesFromList [Attribute "a" DateTimeAtomType]) [[DateTimeAtom (posixSecondsToUTCTime(realToFrac (1495199790 :: Int)))]]),@@ -588,3 +593,42 @@   executeTutorialD sessionId dbconn "createarbitraryrelation rv1 {a Integer} 5-10"   executeTutorialD sessionId dbconn "createarbitraryrelation rv2 {a Integer, b relation{c Integer}} 10-100"   executeTutorialD sessionId dbconn "createarbitraryrelation rv3 {a Int, b relation{c Interval Int}} 3-100"+  +testNonEmptyListType :: Test+testNonEmptyListType = TestCase $ do+  --create a NonEmptyList+  (sessionId, dbconn) <- dateExamplesConnection emptyNotificationCallback  +  executeTutorialD sessionId dbconn "x:=relation{tuple{a NECons 3 (Cons 4 Empty)}} : {x:=nonEmptyListHead(@a)}"+  eX <- executeRelationalExpr sessionId dbconn (RelationVariable "x" ())+  let expected = mkRelationFromList attrs [[nelist, nehead]]+      attrs = attributesFromList [Attribute "a" neListType,+                                  Attribute "x" IntegerAtomType]+      neListType = nonEmptyListAtomType IntegerAtomType+      listType = listAtomType IntegerAtomType+      nelist = ConstructedAtom "NECons" (nonEmptyListAtomType IntegerAtomType) [+        IntegerAtom 3,+        ConstructedAtom "Cons" listType [IntegerAtom 4, ConstructedAtom "Empty" listType []]]+      nehead = IntegerAtom 3+  assertEqual "non-empty list type construction" expected eX+  +testUnresolvedAtomTypes :: Test+testUnresolvedAtomTypes = TestCase $ do+  (sessionId, dbconn) <- dateExamplesConnection emptyNotificationCallback+  let err1 = "TypeConstructorTypeVarMissing"+  expectTutorialDErr sessionId dbconn (T.isPrefixOf err1) "x:=relation{tuple{a Empty}}"+  executeTutorialD sessionId dbconn "x:=relation{a List Int}{tuple{a Empty}}"++-- with (x as s) s    +testWithClause :: Test+testWithClause = TestCase $ do+  (sessionId, dbconn) <- dateExamplesConnection emptyNotificationCallback+  executeTutorialD sessionId dbconn "x:=with (x as s) x"+  eX <- executeRelationalExpr sessionId dbconn (RelationVariable "x" ())+  assertEqual "with x as s" (Right suppliersRel) eX+  +  let err1 = "RelVarAlreadyDefinedError"  +  expectTutorialDErr sessionId dbconn (T.isPrefixOf err1) "x:=with (s as s) s"  +  +  expectTutorialDErr sessionId dbconn (T.isPrefixOf err1) "x:=with (s as sp) s"  ++  
test/TutorialD/Interpreter/DatabaseContextFunctionScript.hs view
@@ -19,10 +19,13 @@   (sess, conn) <- dateExamplesConnection emptyNotificationCallback   let addfunc = "adddatabasecontextfunction \"addTrue2\" DatabaseContext -> Either DatabaseContextFunctionError DatabaseContext  \"\"\"(\\[] ctx -> executeDatabaseContextExpr (Assign \"true2\" (ExistingRelation relationTrue)) ctx) :: [Atom] -> DatabaseContext -> Either DatabaseContextFunctionError DatabaseContext\"\"\""   executeTutorialD sess conn addfunc+  putStrLn "spam1"   executeTutorialD sess conn "execute addTrue2()"+  putStrLn "spam2"+  {-   let true2Expr = RelationVariable "true2" ()   result <- executeRelationalExpr sess conn true2Expr-  assertEqual "simple atom function equality" (Right relationTrue) result+  assertEqual "simple atom function equality" (Right relationTrue) result-}  testErrorDBCFunction :: Test testErrorDBCFunction = TestCase $ do
test/TutorialD/Interpreter/TestBase.hs view
@@ -31,12 +31,12 @@     Right parsed -> do        result <- evalTutorialD sessionId conn UnsafeEvaluation parsed       case result of-        QuitResult -> assertFailure "quit?"-        DisplayResult _ -> assertFailure "display?"-        DisplayIOResult _ -> assertFailure "displayIO?"-        DisplayRelationResult _ -> assertFailure "displayrelation?"-        DisplayParseErrorResult _ _ -> assertFailure "displayparseerrorresult?"-        DisplayErrorResult err -> assertFailure (show err)        +        QuitResult -> putStrLn "yyy" >> assertFailure "quit?"+        DisplayResult _ -> putStrLn "xxx" >> assertFailure "display?"+        DisplayIOResult _ -> putStrLn "z" >> assertFailure "displayIO?"+        DisplayRelationResult _ -> putStrLn "Y" >> assertFailure "displayrelation?"+        DisplayParseErrorResult _ _ -> putStrLn "X" >> assertFailure "displayparseerrorresult?"+        DisplayErrorResult err -> putStrLn "asd" >> assertFailure (show tutd ++ ": " ++ show err)                 QuietSuccessResult -> pure ()          expectTutorialDErr :: SessionId -> Connection -> (Text -> Bool) -> Text -> IO ()