packages feed

project-m36 0.9.4 → 0.9.5

raw patch · 48 files changed

+570/−266 lines, 48 filesdep +fast-builderdep +scientificdep +time-compatdep −hashable-timedep ~basedep ~curryer-rpcdep ~ghcPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: fast-builder, scientific, time-compat

Dependencies removed: hashable-time

Dependency ranges changed: base, curryer-rpc, ghc, winery

API changes (from Hackage documentation)

- ProjectM36.Base: instance Data.Hashable.Class.Hashable (ProjectM36.Base.FunctionBody a)
- ProjectM36.Persist: writeBSFileSync :: DiskSync -> FilePath -> ByteString -> IO ()
- ProjectM36.Serialise.Base: instance Codec.Winery.Class.Serialise a => Codec.Winery.Class.Serialise (GHC.Base.NonEmpty a)
+ ProjectM36.AtomFunctionError: AtomFunctionParseError :: String -> AtomFunctionError
+ ProjectM36.AtomFunctions.Primitive: scientificAtomFunctions :: AtomFunctions
+ ProjectM36.Base: ScientificAtom :: !Scientific -> Atom
+ ProjectM36.Base: ScientificAtomType :: AtomType
+ ProjectM36.Base: attributesContainRelationAtomType :: Attributes -> Bool
+ ProjectM36.Client: ScientificAtom :: !Scientific -> Atom
+ ProjectM36.Client: ScientificAtomType :: AtomType
+ ProjectM36.Client.Simple: ScientificAtom :: !Scientific -> Atom
+ ProjectM36.Client.Simple: ScientificAtomType :: AtomType
+ ProjectM36.IsomorphicSchema: relationVariablesAsRelationInSchema :: DatabaseContext -> Schema -> TransactionGraph -> Either RelationalError Relation
+ ProjectM36.Persist: writeSerialiseSync :: Serialise a => DiskSync -> FilePath -> a -> IO ()
+ ProjectM36.Trace: traceBlock :: String -> IO () -> IO ()
+ ProjectM36.TransactionGraph.Persist: One :: Pos
+ ProjectM36.TransactionGraph.Persist: Two :: Pos
+ ProjectM36.TransactionGraph.Persist: data Pos
+ ProjectM36.TransactionGraph.Persist: twowords :: String -> (String, String)
- ProjectM36.Base: BoolAtom :: Bool -> Atom
+ ProjectM36.Base: BoolAtom :: !Bool -> Atom
- ProjectM36.Base: ByteStringAtom :: ByteString -> Atom
+ ProjectM36.Base: ByteStringAtom :: !ByteString -> Atom
- ProjectM36.Base: ConstructedAtom :: DataConstructorName -> AtomType -> [Atom] -> Atom
+ ProjectM36.Base: ConstructedAtom :: !DataConstructorName -> !AtomType -> [Atom] -> Atom
- ProjectM36.Base: DateTimeAtom :: UTCTime -> Atom
+ ProjectM36.Base: DateTimeAtom :: !UTCTime -> Atom
- ProjectM36.Base: DayAtom :: Day -> Atom
+ ProjectM36.Base: DayAtom :: !Day -> Atom
- ProjectM36.Base: DifferenceF :: r_azyf -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: DifferenceF :: r_aANh -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: DoubleAtom :: Double -> Atom
+ ProjectM36.Base: DoubleAtom :: !Double -> Atom
- ProjectM36.Base: EqualsF :: r_azyf -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: EqualsF :: r_aANh -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: ExistingRelationF :: Relation -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: ExistingRelationF :: Relation -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: ExtendF :: ExtendTupleExprBase a_apAG -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: ExtendF :: ExtendTupleExprBase a_aqKl -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: GroupF :: AttributeNamesBase a_apAG -> Text -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: GroupF :: AttributeNamesBase a_aqKl -> Text -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: IntAtom :: Int -> Atom
+ ProjectM36.Base: IntAtom :: !Int -> Atom
- ProjectM36.Base: IntegerAtom :: Integer -> Atom
+ ProjectM36.Base: IntegerAtom :: !Integer -> Atom
- ProjectM36.Base: JoinF :: r_azyf -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: JoinF :: r_aANh -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: MakeRelationFromExprsF :: Maybe [AttributeExprBase a_apAG] -> TupleExprsBase a_apAG -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: MakeRelationFromExprsF :: Maybe [AttributeExprBase a_aqKl] -> TupleExprsBase a_aqKl -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: MakeStaticRelationF :: Attributes -> RelationTupleSet -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: MakeStaticRelationF :: Attributes -> RelationTupleSet -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: NotEqualsF :: r_azyf -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: NotEqualsF :: r_aANh -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: ProjectF :: AttributeNamesBase a_apAG -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: ProjectF :: AttributeNamesBase a_aqKl -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: RelationAtom :: Relation -> Atom
+ ProjectM36.Base: RelationAtom :: !Relation -> Atom
- ProjectM36.Base: RelationVariableF :: Text -> a_apAG -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: RelationVariableF :: Text -> a_aqKl -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: RelationalExprAtom :: RelationalExpr -> Atom
+ ProjectM36.Base: RelationalExprAtom :: !RelationalExpr -> Atom
- ProjectM36.Base: RenameF :: Text -> Text -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: RenameF :: Text -> Text -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: RestrictF :: RestrictionPredicateExprBase a_apAG -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: RestrictF :: RestrictionPredicateExprBase a_aqKl -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: TextAtom :: Text -> Atom
+ ProjectM36.Base: TextAtom :: !Text -> Atom
- ProjectM36.Base: UUIDAtom :: UUID -> Atom
+ ProjectM36.Base: UUIDAtom :: !UUID -> Atom
- ProjectM36.Base: UngroupF :: Text -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: UngroupF :: Text -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: UnionF :: r_azyf -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: UnionF :: r_aANh -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: WithF :: [(WithNameExprBase a_apAG, r_azyf)] -> r_azyf -> RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: WithF :: [(WithNameExprBase a_aqKl, r_aANh)] -> r_aANh -> RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Base: data RelationalExprBaseF (a_apAG :: Type) r_azyf
+ ProjectM36.Base: data RelationalExprBaseF (a_aqKl :: Type) r_aANh
- ProjectM36.Client: BoolAtom :: Bool -> Atom
+ ProjectM36.Client: BoolAtom :: !Bool -> Atom
- ProjectM36.Client: ByteStringAtom :: ByteString -> Atom
+ ProjectM36.Client: ByteStringAtom :: !ByteString -> Atom
- ProjectM36.Client: ConstructedAtom :: DataConstructorName -> AtomType -> [Atom] -> Atom
+ ProjectM36.Client: ConstructedAtom :: !DataConstructorName -> !AtomType -> [Atom] -> Atom
- ProjectM36.Client: DateTimeAtom :: UTCTime -> Atom
+ ProjectM36.Client: DateTimeAtom :: !UTCTime -> Atom
- ProjectM36.Client: DayAtom :: Day -> Atom
+ ProjectM36.Client: DayAtom :: !Day -> Atom
- ProjectM36.Client: DoubleAtom :: Double -> Atom
+ ProjectM36.Client: DoubleAtom :: !Double -> Atom
- ProjectM36.Client: IntAtom :: Int -> Atom
+ ProjectM36.Client: IntAtom :: !Int -> Atom
- ProjectM36.Client: IntegerAtom :: Integer -> Atom
+ ProjectM36.Client: IntegerAtom :: !Integer -> Atom
- ProjectM36.Client: RelationAtom :: Relation -> Atom
+ ProjectM36.Client: RelationAtom :: !Relation -> Atom
- ProjectM36.Client: RelationalExprAtom :: RelationalExpr -> Atom
+ ProjectM36.Client: RelationalExprAtom :: !RelationalExpr -> Atom
- ProjectM36.Client: TextAtom :: Text -> Atom
+ ProjectM36.Client: TextAtom :: !Text -> Atom
- ProjectM36.Client: UUIDAtom :: UUID -> Atom
+ ProjectM36.Client: UUIDAtom :: !UUID -> Atom
- ProjectM36.Client.Simple: BoolAtom :: Bool -> Atom
+ ProjectM36.Client.Simple: BoolAtom :: !Bool -> Atom
- ProjectM36.Client.Simple: ByteStringAtom :: ByteString -> Atom
+ ProjectM36.Client.Simple: ByteStringAtom :: !ByteString -> Atom
- ProjectM36.Client.Simple: ConstructedAtom :: DataConstructorName -> AtomType -> [Atom] -> Atom
+ ProjectM36.Client.Simple: ConstructedAtom :: !DataConstructorName -> !AtomType -> [Atom] -> Atom
- ProjectM36.Client.Simple: DateTimeAtom :: UTCTime -> Atom
+ ProjectM36.Client.Simple: DateTimeAtom :: !UTCTime -> Atom
- ProjectM36.Client.Simple: DayAtom :: Day -> Atom
+ ProjectM36.Client.Simple: DayAtom :: !Day -> Atom
- ProjectM36.Client.Simple: DoubleAtom :: Double -> Atom
+ ProjectM36.Client.Simple: DoubleAtom :: !Double -> Atom
- ProjectM36.Client.Simple: IntAtom :: Int -> Atom
+ ProjectM36.Client.Simple: IntAtom :: !Int -> Atom
- ProjectM36.Client.Simple: IntegerAtom :: Integer -> Atom
+ ProjectM36.Client.Simple: IntegerAtom :: !Integer -> Atom
- ProjectM36.Client.Simple: RelationAtom :: Relation -> Atom
+ ProjectM36.Client.Simple: RelationAtom :: !Relation -> Atom
- ProjectM36.Client.Simple: RelationalExprAtom :: RelationalExpr -> Atom
+ ProjectM36.Client.Simple: RelationalExprAtom :: !RelationalExpr -> Atom
- ProjectM36.Client.Simple: TextAtom :: Text -> Atom
+ ProjectM36.Client.Simple: TextAtom :: !Text -> Atom
- ProjectM36.Client.Simple: UUIDAtom :: UUID -> Atom
+ ProjectM36.Client.Simple: UUIDAtom :: !UUID -> Atom

Files

Changelog.markdown view
@@ -1,3 +1,12 @@+# 2022-08-19 (v0.9.5)+  +* removed necessity for caret "^" when using boolean atom expressions in restriction predicates+* `True` and `False` are now value constructors for `Bool` atom values (previously `t` and `f); changed for better discoverability by Haskell developers+* add `Scientific` data type for arbitrary-precision values (backed by Data.Scientific)+* add support for GHC 9.0 and GHC 9.2+* drop support for GHC < 8.10.7+* fix relational equality when the relation includes a nested relation+	 # 2021-12-05 (v0.9.4)  * fix bug which [caused tuple storage to be duplicated unnecessarily](https://github.com/agentm/project-m36/pull/328)
README.markdown view
@@ -61,6 +61,7 @@ 1. [Developer's Change Log](Changelog.markdown) 1. [Simple Client API](docs/simple_api.markdown) 1. [CSV Import/Export](docs/import_export_csv.markdown)+1. [Developer Setup](docs/dev_setup.markdown)  ### Database Comparisons @@ -94,7 +95,7 @@  ## Development -Project:M36 is developed in Haskell and compiled with GHC 8.6 or later.+Project:M36 is developed in Haskell and compiled with GHC 8.8 or later.  ## Related Projects 
examples/DerivingCustomTupleable.hs view
@@ -4,7 +4,6 @@ import ProjectM36.Atomable (Atomable) import Control.DeepSeq (NFData) import Data.Text (Text)-import GHC.Generics (Generic) import Codec.Winery  newtype BlogId = BlogId { getBlogId :: Int }
examples/blog.hs view
@@ -29,7 +29,7 @@ import Text.Blaze.Html.Renderer.Text import Control.Monad.IO.Class (liftIO) import Network.HTTP.Types.Status-import Data.Time.Format+import Data.Time.Format.ISO8601  --define your data types data Blog = Blog {@@ -166,7 +166,7 @@                                                           blogRestrictionExpr                                                            (RelationVariable "blog" ())))   let render = html . renderHtml-      formatStamp = formatTime defaultTimeLocale (iso8601DateFormat (Just "%H:%M:%S"))+      formatStamp = iso8601Show --formatTime defaultTimeLocale (iso8601DateFormat (Just "%H:%M:%S"))   case eRel of      Left err -> render500 (toHtml (show err))     --handle successful query execution
project-m36.cabal view
@@ -1,6 +1,6 @@ Cabal-Version: 2.2 Name: project-m36-Version: 0.9.4+Version: 0.9.5 License: MIT --note that this license specification is erroneous and only labeled MIT to appease hackage which does not recognize public domain packages in cabal >2.2- Project:M36 is dedicated to the public domain Build-Type: Simple@@ -35,9 +35,9 @@      Default: True  Library-    Build-Depends: base>=4.8 && < 4.15, ghc-paths, mtl, containers, unordered-containers, hashable, haskeline, directory, MonadRandom, random-shuffle, uuid >= 1.3.12, cassava >= 0.4.5.1 && < 0.6, text, bytestring, deepseq, deepseq-generics, vector, parallel, monad-parallel, exceptions, transformers, gnuplot, filepath, zlib, directory, temporary, stm, time, hashable-time, old-locale, rset, attoparsec, either, base64-bytestring, data-interval, extended-reals, aeson >= 1.1, path-pieces, conduit, resourcet, http-api-data, semigroups, QuickCheck, quickcheck-instances, list-t, stm-containers >= 0.2.15, foldl, optparse-applicative, Glob, cryptohash-sha256, text-manipulate >= 0.2.0.1 && < 0.4, winery, curryer-rpc, network, async, vector-instances, recursion-schemes, streamly >= 0.7.2, convertible+    Build-Depends: base>=4.8 && < 4.17, ghc-paths, mtl, containers, unordered-containers, hashable, haskeline, directory, MonadRandom, random-shuffle, uuid >= 1.3.12, cassava >= 0.4.5.1 && < 0.6, text, bytestring, deepseq, deepseq-generics, vector, parallel, monad-parallel, exceptions, transformers, gnuplot, filepath, zlib, directory, temporary, stm, time, old-locale, rset, attoparsec, either, base64-bytestring, data-interval, extended-reals, aeson >= 1.1, path-pieces, conduit, resourcet, http-api-data, semigroups, QuickCheck, quickcheck-instances, list-t, stm-containers >= 0.2.15, foldl, optparse-applicative, Glob, cryptohash-sha256, text-manipulate >= 0.2.0.1 && < 0.4, winery >= 1.4, curryer-rpc>=0.2.2, network, async, vector-instances, recursion-schemes, streamly >= 0.7.2, convertible, fast-builder, scientific, time-compat >= 1.9.6.1     if flag(haskell-scripting)-        Build-Depends: ghc >= 8.2 && < 8.11+        Build-Depends: ghc >= 8.2 && < 9.3         CPP-Options: -DPM36_HASKELL_SCRIPTING     if impl(ghc>= 8) && flag(haskell-scripting)       build-depends:@@ -130,27 +130,28 @@                      ProjectM36.GraphRefRelationalExpr,                      ProjectM36.NormalizeExpr,                      ProjectM36.TransactionInfo,-                     ProjectM36.WithNameExpr+                     ProjectM36.WithNameExpr, +                     ProjectM36.Trace     GHC-Options: -Wall -rdynamic     if os(windows)       Build-Depends: Win32 >= 2.5.4.1       Other-Modules: ProjectM36.Win32Handle     else       --219-  too many exported symbols under Windows and GHC 8.4-      GHC-Options: -rdynamic -fexternal-interpreter+      GHC-Options: -rdynamic -fexternal-interpreter -eventlog       C-sources: cbits/DirectoryFsync.c, cbits/darwin_statfs.c       Build-Depends: unix     CC-Options: -fPIC     Hs-Source-Dirs: ./src/lib     Default-Language: Haskell2010-    Default-Extensions: OverloadedStrings, CPP+    Default-Extensions: OverloadedStrings, CPP, LambdaCase     if !flag(stack)-      Build-Depends: deferred-folds+      Build-Depends: deferred-folds   Executable tutd     if flag(haskell-scripting)-        Build-Depends: ghc >= 8.2 && < 8.11-    Build-Depends: base >=4.8 && <5.0,+        Build-Depends: ghc >= 8.2 && < 9.3+    Build-Depends: base >=4.8,                    ghc-paths,                    project-m36,                    containers,@@ -165,7 +166,6 @@                    vector,                    text,                    time,-                   hashable-time,                    bytestring,                    stm,                    deepseq,@@ -210,21 +210,23 @@                    TutorialD.Interpreter.Types,                    TutorialD.Interpreter.SchemaOperator,                    TutorialD.Interpreter.TransGraphRelationalOperator,-                   TutorialD.Interpreter.SchemaOperator+                   TutorialD.Interpreter.SchemaOperator,                    TutorialD.Printer     main-is: TutorialD/tutd.hs     CC-Options: -fPIC     if os(windows)-      GHC-Options: -Wall -threaded+      GHC-Options: -Wall -threaded -eventlog -rtsopts     else-      GHC-Options: -Wall -threaded -rdynamic+      GHC-Options: -Wall -threaded -rdynamic -eventlog -rtsopts+    if flag(profiler)+      GHC-Prof-Options: -fprof-auto -rtsopts -threaded     Hs-Source-Dirs: ./src/bin     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings  Executable project-m36-server     if flag(haskell-scripting)-        Build-Depends: ghc >= 8.2 && < 8.11+        Build-Depends: ghc >= 8.2 && < 9.3     Build-Depends: base,                    ghc-paths,                    transformers,@@ -239,7 +241,6 @@                    parallel,                    bytestring,                    optparse-applicative,-                   hashable-time,                    time,                    text,                    deepseq-generics,@@ -251,12 +252,13 @@                    http-api-data,                    stm-containers,                    list-t,-                   base64-bytestring+                   base64-bytestring,+                   scientific     Main-Is: ./src/bin/ProjectM36/Server/project-m36-server.hs     if os(windows)       GHC-Options: -Wall -threaded -rtsopts     else-      GHC-Options: -Wall -threaded -rtsopts -rdynamic      +      GHC-Options: -Wall -threaded -rtsopts -rdynamic     if flag(profiler)       GHC-Prof-Options: -fprof-auto -rtsopts -threaded -Wall     Default-Language: Haskell2010@@ -265,7 +267,7 @@ Executable bigrel     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, optparse-applicative, stm-containers, list-t, ghc, ghc-paths, transformers, project-m36, random, MonadRandom, semigroups, parser-combinators+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, optparse-applicative, stm-containers, list-t, ghc, ghc-paths, transformers, project-m36, random, MonadRandom, semigroups, parser-combinators     Other-Modules: TutorialD.Interpreter.Base,                    TutorialD.Interpreter.DatabaseContextExpr,                    TutorialD.Interpreter.RelationalExpr,@@ -274,11 +276,11 @@     GHC-Options: -Wall -threaded -rtsopts     HS-Source-Dirs: ./src/bin     if flag(profiler)-      GHC-Prof-Options: -fprof-auto -rtsopts -threaded -Wall+      GHC-Prof-Options: -fprof-auto -rtsopts -threaded -Wall -eventlog  Common commontest     Default-Language: Haskell2010-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics,parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, websockets, optparse-applicative, network, aeson, project-m36, random, MonadRandom, semigroups, parser-combinators, winery, curryer-rpc, prettyprinter, base64-bytestring, modern-uri, http-types, http-conduit, base16-bytestring,cryptohash-sha256+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics,parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, websockets, optparse-applicative, network, aeson, project-m36, random, MonadRandom, semigroups, parser-combinators, winery, curryer-rpc, prettyprinter, base64-bytestring, modern-uri, http-types, http-conduit, base16-bytestring, cryptohash-sha256, scientific     Default-Extensions: OverloadedStrings     GHC-Options: -Wall -threaded     Hs-Source-Dirs: test, src/bin@@ -311,7 +313,7 @@     type: exitcode-stdio-1.0     main-is: TutorialD/InterpreterTest.hs     Other-Modules: TutorialD.Interpreter, TutorialD.Interpreter.Base, TutorialD.Interpreter.Export.Base, TutorialD.Interpreter.Export.CSV, TutorialD.Interpreter.Import.Base, TutorialD.Interpreter.Import.CSV, TutorialD.Interpreter.Import.TutorialD, TutorialD.Interpreter.RODatabaseContextOperator, TutorialD.Interpreter.RelationalExpr, TutorialD.Interpreter.TransactionGraphOperator, TutorialD.Interpreter.Types, TutorialD.Interpreter.DatabaseContextExpr, TutorialD.Interpreter.InformationOperator, TutorialD.Interpreter.Import.BasicExamples, TutorialD.Interpreter.DatabaseContextIOOperator, TutorialD.Interpreter.TestBase, TutorialD.Interpreter.TransGraphRelationalOperator, TutorialD.Interpreter.SchemaOperator, TutorialD.Printer-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, stm-containers, list-t, project-m36, random, MonadRandom, semigroups, parser-combinators, prettyprinter+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, stm-containers, list-t, project-m36, random, MonadRandom, semigroups, parser-combinators, prettyprinter, scientific  Test-Suite test-tutoriald-atomfunctionscript     import: commontest@@ -383,28 +385,28 @@ Executable Example-SimpleClient     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics,parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, ghc, ghc-paths, project-m36, random, MonadRandom+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics,parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, ghc, ghc-paths, project-m36, random, MonadRandom     Main-Is: examples/SimpleClient.hs     GHC-Options: -Wall -threaded  Executable Example-OutOfTheTarpit     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics,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, winery+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics,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, winery     Main-Is: examples/out_of_the_tarpit.hs     GHC-Options: -Wall -threaded  Executable Example-Blog     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics,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, scotty, blaze-html, http-types, winery+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics,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, scotty, blaze-html, http-types, winery     Main-Is: examples/blog.hs     GHC-Options: -Wall -threaded  Executable Example-Hair     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics,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, winery+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics,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, winery     Main-Is: examples/hair.hs     GHC-Options: -Wall -threaded @@ -418,7 +420,7 @@ Executable Example-CustomTupleable     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics,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, winery+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics,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, winery     Main-Is: examples/CustomTupleable.hs     GHC-Options: -Wall -threaded @@ -440,7 +442,7 @@  Executable project-m36-websocket-server     Default-Language: Haskell2010-    Build-Depends: base, aeson, path-pieces, either, conduit, http-api-data, template-haskell, websockets, aeson, optparse-applicative, project-m36, containers, bytestring, text, vector, uuid, megaparsec, haskeline, mtl, directory, base64-bytestring, random, MonadRandom, time, semigroups, attoparsec, parser-combinators, prettyprinter, network, modern-uri, http-conduit, base16-bytestring, http-types, cryptohash-sha256, wai, wai-websockets, warp, warp-tls+    Build-Depends: base, aeson, path-pieces, either, conduit, http-api-data, template-haskell, websockets, aeson, optparse-applicative, project-m36, containers, bytestring, text, vector, uuid, megaparsec, haskeline, mtl, directory, base64-bytestring, random, MonadRandom, time, semigroups, attoparsec, parser-combinators, prettyprinter, network, modern-uri, http-conduit, base16-bytestring, http-types, cryptohash-sha256, wai, wai-websockets, warp, warp-tls, scientific     Main-Is: ProjectM36/Server/WebSocket/websocket-server.hs     Other-Modules:  ProjectM36.Client.Json, ProjectM36.Server.RemoteCallTypes.Json, ProjectM36.Server.WebSocket, TutorialD.Interpreter, TutorialD.Interpreter.Base, TutorialD.Interpreter.DatabaseContextExpr, TutorialD.Interpreter.DatabaseContextIOOperator, TutorialD.Interpreter.Export.Base, TutorialD.Interpreter.Export.CSV, TutorialD.Interpreter.Import.Base, TutorialD.Interpreter.Import.BasicExamples, TutorialD.Interpreter.Import.CSV, TutorialD.Interpreter.Import.TutorialD, TutorialD.Interpreter.InformationOperator, TutorialD.Interpreter.RODatabaseContextOperator, TutorialD.Interpreter.RelationalExpr, TutorialD.Interpreter.TransactionGraphOperator, TutorialD.Interpreter.Types, TutorialD.Interpreter.TransGraphRelationalOperator, TutorialD.Interpreter.SchemaOperator, TutorialD.Printer     GHC-Options: -Wall -threaded@@ -489,7 +491,7 @@ Executable handles     Default-Language: Haskell2010     Default-Extensions: OverloadedStrings-    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics,parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, optparse-applicative, stm-containers, list-t, ghc, ghc-paths, transformers, project-m36, random, MonadRandom, semigroups, parser-combinators, prettyprinter, modern-uri, http-types, http-conduit, base16-bytestring, cryptohash-sha256+    Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, time, bytestring, uuid, stm, deepseq, deepseq-generics,parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, optparse-applicative, stm-containers, list-t, ghc, ghc-paths, transformers, project-m36, random, MonadRandom, semigroups, parser-combinators, prettyprinter, modern-uri, http-types, http-conduit, base16-bytestring, cryptohash-sha256     main-is: benchmark/Handles.hs     Other-Modules: TutorialD.Interpreter,       TutorialD.Interpreter.Base,@@ -507,7 +509,7 @@       TutorialD.Interpreter.SchemaOperator,       TutorialD.Interpreter.TransGraphRelationalOperator,       TutorialD.Interpreter.TransactionGraphOperator,-      TutorialD.Interpreter.Types+      TutorialD.Interpreter.Types,       TutorialD.Printer     GHC-Options: -Wall -threaded -rtsopts     HS-Source-Dirs: ./src/bin
src/bin/ProjectM36/Server/RemoteCallTypes/Json.hs view
@@ -18,6 +18,7 @@ import Data.Text.Encoding import Data.Time.Calendar import Data.UUID+import Data.Scientific  instance ToJSON RelationalExpr instance FromJSON RelationalExpr@@ -92,6 +93,8 @@                                      "val" .= i ]   toJSON atom@(DoubleAtom i) = object [ "type" .= atomTypeForAtom atom,                                         "val" .= i ]+  toJSON atom@(ScientificAtom i) = object [ "type" .= atomTypeForAtom atom,+                                        "val" .= (coefficient i, base10Exponent i) ]   toJSON atom@(TextAtom i) = object [ "type" .= atomTypeForAtom atom,                                       "val" .= i ]   toJSON atom@(DayAtom i) = object [ "type" .= atomTypeForAtom atom,@@ -123,6 +126,9 @@       RelationAtomType _ -> RelationAtom <$> o .: "val"       IntAtomType -> IntAtom <$> o .: "val"       IntegerAtomType -> IntegerAtom <$> o .: "val"+      ScientificAtomType -> do+        (c,e) <- o .: "val"+        pure (ScientificAtom (scientific c e))       DoubleAtomType -> DoubleAtom <$> o .: "val"       TextAtomType -> TextAtom <$> o .: "val"       DayAtomType -> do
src/bin/ProjectM36/Server/WebSocket/websocket-server.hs view
@@ -2,7 +2,7 @@  import Control.Concurrent import Control.Exception-import Control.Monad (when)+import Control.Monad (when, void) import Data.Maybe (isJust) import Data.String (fromString) import Network.HTTP.Types (status400)@@ -35,7 +35,7 @@   when (isJust configCertificateFile /= isJust configKeyFile) $     throwIO $ ErrorCall "TLS_CERTIFICATE_PATH and TLS_KEY_PATH must be set in tandem" -  _ <- forkFinally (launchServer serverConfig' (Just addressMVar) >> pure ()) (either throwIO pure)+  _ <- forkFinally (void (launchServer serverConfig' (Just addressMVar))) (either throwIO pure)   --wait for server to be listening   addr <- takeMVar addressMVar   let port =
src/bin/TutorialD/Interpreter/RelationalExpr.hs view
@@ -150,16 +150,13 @@ relExprP :: RelationalMarkerExpr a => Parser (RelationalExprBase a) relExprP = try withMacroExprP <|> makeExprParser relTerm relOperators -relVarNameP :: Parser RelVarName-relVarNameP = try uncapitalizedIdentifier <|> quotedIdentifier- relVarP :: RelationalMarkerExpr a => Parser (RelationalExprBase a) relVarP = RelationVariable <$> relVarNameP <*> parseMarkerP  relTerm :: RelationalMarkerExpr a => Parser (RelationalExprBase a) relTerm = parens relExprP           <|> makeRelationP-          <|> relVarP+          <|> (relVarP <* notFollowedBy "(")  restrictionPredicateP :: RelationalMarkerExpr a => Parser (RestrictionPredicateExprBase a) restrictionPredicateP = makeExprParser predicateTerm predicateOperators@@ -170,14 +167,14 @@       [InfixL (reservedOp "or" >> return OrPredicate)]       ]     predicateTerm = try (parens restrictionPredicateP)-                    <|> try restrictionAtomExprP                     <|> try restrictionAttributeEqualityP-                    <|> relationalBooleanExprP+                    <|> try relationalBooleanExprP+                    <|> restrictionAtomExprP                                         + relationalBooleanExprP :: RelationalMarkerExpr a => Parser (RestrictionPredicateExprBase a)-relationalBooleanExprP =+relationalBooleanExprP = RelationalExprPredicate <$> (parens relExprP <|> relTerm)   --we can't actually detect if the type is relational boolean, so we just pass it to the next phase-  RelationalExprPredicate <$> (parens relExprP <|> relTerm)  restrictionAttributeEqualityP :: RelationalMarkerExpr a => Parser (RestrictionPredicateExprBase a) restrictionAttributeEqualityP = do@@ -185,10 +182,8 @@   reservedOp "="   AttributeEqualityPredicate attributeName <$> atomExprP -restrictionAtomExprP :: RelationalMarkerExpr a=> Parser (RestrictionPredicateExprBase a) --atoms which are of type "boolean"-restrictionAtomExprP = do-  _ <- char '^' -- not ideal, but allows me to continue to use a context-free grammar-  (try (char 't') >> pure TruePredicate) <|> (try (char 'f') >> pure (NotPredicate TruePredicate)) <|> AtomExprPredicate <$> atomExprP+restrictionAtomExprP :: RelationalMarkerExpr a => Parser (RestrictionPredicateExprBase a) --atoms which are of type "boolean"+restrictionAtomExprP = AtomExprPredicate <$> consumeAtomExprP False  multiTupleExpressionP :: RelationalMarkerExpr a => Parser [ExtendTupleExprBase a] multiTupleExpressionP = sepBy extendTupleExpressionP comma@@ -254,7 +249,7 @@ boolAtomP :: Parser Atom boolAtomP = do   v <- identifier-  if v == "t" || v == "f" then+  if v == "True" || v == "False" then     pure $ BoolAtom (v == "t")         else     fail "invalid boolAtom"
src/bin/TutorialD/Interpreter/Types.hs view
@@ -69,5 +69,5 @@                        TypeVariable <$> typeVariableIdentifierP                     --+relVarNameP :: Parser RelVarName+relVarNameP = try uncapitalizedIdentifier <|> quotedIdentifier
src/bin/TutorialD/Printer.hs view
@@ -19,6 +19,7 @@ instance Pretty Atom where   pretty (IntegerAtom x) = pretty x   pretty (IntAtom x) = "int" <> parensList [pretty x]+  pretty (ScientificAtom s) = "scientific" <> parensList [dquotes (pretty (show s))]   pretty (DoubleAtom x) = pretty x   pretty (TextAtom x) = dquotes (pretty x)   pretty (DayAtom x) = "fromGregorian" <> parensList [pretty a, pretty b, pretty c]@@ -26,7 +27,7 @@       (a,b,c) = toGregorian x   pretty (DateTimeAtom time) = "dateTimeFromEpochSeconds" <> parensList [pretty @Integer (round (utcTimeToPOSIXSeconds time))]   pretty (ByteStringAtom bs) = "bytestring" <> parensList [dquotes (pretty (TE.decodeUtf8 (B64.encode bs)))]-  pretty (BoolAtom x) = if x then "t" else "f"+  pretty (BoolAtom x) = if x then "True" else "False"   pretty (UUIDAtom u) = pretty u   pretty (RelationAtom x) = pretty x   pretty (RelationalExprAtom re) = pretty re@@ -70,7 +71,7 @@   pretty (Relation attrs tupSet) = "relation" <> prettyBracesList (A.toList attrs) <> prettyBracesList (asList tupSet)  instance Pretty Attribute where-  pretty (Attribute n aTy) = pretty n <+> pretty (show aTy)  -- workaround+  pretty (Attribute n aTy) = pretty n <+> pretty aTy  instance Pretty RelationalExpr where   pretty (RelationVariable n _) = pretty n@@ -129,6 +130,7 @@ instance Pretty AtomType where   pretty IntAtomType = "Int"   pretty IntegerAtomType = "Integer"+  pretty ScientificAtomType = "Scientific"   pretty DoubleAtomType = "Double"   pretty TextAtomType = "Text"   pretty DayAtomType = "Day"
src/lib/ProjectM36/Arbitrary.hs view
@@ -18,10 +18,14 @@ import Data.Time import Control.Monad.Reader import Data.UUID+import Data.Scientific  arbitrary' :: AtomType -> WithTCMap Gen (Either RelationalError Atom) arbitrary' IntegerAtomType =    Right . IntegerAtom <$> lift (arbitrary :: Gen Integer)++arbitrary' ScientificAtomType =+  Right . ScientificAtom <$> lift (arbitrary :: Gen Scientific)  arbitrary' (RelationAtomType attrs)  = do   tcMap <-ask
src/lib/ProjectM36/Atom.hs view
@@ -14,6 +14,7 @@ atomToText :: Atom -> T.Text atomToText (IntegerAtom i) = (T.pack . show) i atomToText (IntAtom i) = (T.pack . show) i+atomToText (ScientificAtom s) = (T.pack . show) s atomToText (DoubleAtom i) = (T.pack . show) i atomToText (TextAtom i) = (T.pack . show) i --quotes necessary for ConstructedAtom subatoms atomToText (DayAtom i) = (T.pack . show) i
src/lib/ProjectM36/AtomFunction.hs view
@@ -29,7 +29,11 @@ emptyAtomFunction :: FunctionName -> AtomFunction emptyAtomFunction name = Function { funcName = name,                                     funcType = [TypeVariableType "a", TypeVariableType "a"],-                                    funcBody = FunctionBuiltInBody (\(x:_) -> pure x) }+                                    funcBody = FunctionBuiltInBody $+                                               \case+                                                 x:_ -> pure x+                                                 _ -> Left AtomFunctionTypeMismatchError+                                  }                                                                                       -- | AtomFunction constructor for compiled-in functions.
src/lib/ProjectM36/AtomFunctionError.hs view
@@ -6,6 +6,7 @@  data AtomFunctionError = AtomFunctionUserError String |                          AtomFunctionTypeMismatchError |+                         AtomFunctionParseError String |                          InvalidIntervalOrderingError |                          InvalidIntervalBoundariesError |                          InvalidIntBoundError |
src/lib/ProjectM36/AtomFunctions/Primitive.hs view
@@ -9,28 +9,45 @@ import Control.Monad import qualified Data.UUID as U import qualified Data.Text as T+import qualified Data.Attoparsec.Text as APT+import Data.Scientific  primitiveAtomFunctions :: AtomFunctions primitiveAtomFunctions = HS.fromList [   --match on any relation type   Function { funcName = "add",              funcType = [IntegerAtomType, IntegerAtomType, IntegerAtomType],-             funcBody = body (\(IntegerAtom i1:IntegerAtom i2:_) -> pure (IntegerAtom (i1 + i2)))},+             funcBody = body (\case+                                 IntegerAtom i1:IntegerAtom i2:_ -> pure (IntegerAtom (i1 + i2))+                                 _ -> Left AtomFunctionTypeMismatchError)},     Function { funcName = "id",                funcType = [TypeVariableType "a", TypeVariableType "a"],-               funcBody = body (\(x:_) -> pure x)},+               funcBody = body (\case+                                   x:_ -> pure x+                                   _ -> Left AtomFunctionTypeMismatchError+                               )},     Function { funcName = "sum",                funcType = foldAtomFuncType IntegerAtomType IntegerAtomType,-               funcBody = body (\(RelationAtom rel:_) -> relationSum rel)},+               funcBody = body $ relationAtomFunc relationSum+             },     Function { funcName = "count",                funcType = foldAtomFuncType (TypeVariableType "a") IntegerAtomType,-               funcBody = body (\(RelationAtom relIn:_) -> relationCount relIn)},+               funcBody = body $ relationAtomFunc relationCount+             },     Function { funcName = "max",                funcType = foldAtomFuncType IntegerAtomType IntegerAtomType,-               funcBody = body (\(RelationAtom relIn:_) -> relationMax relIn)},+               funcBody = body $ relationAtomFunc relationMax +             },     Function { funcName = "min",                funcType = foldAtomFuncType IntegerAtomType IntegerAtomType,-               funcBody = body (\(RelationAtom relIn:_) -> relationMin relIn)},+               funcBody = body $ relationAtomFunc relationMin+             },+    Function { funcName = "eq",+               funcType = [IntegerAtomType, IntegerAtomType, BoolAtomType],+               funcBody = body $ \case+                                         [i1,i2] -> pure (BoolAtom (i1 == i2))+                                         _ -> Left AtomFunctionTypeMismatchError+             },     Function { funcName = "lt",                funcType = [IntegerAtomType, IntegerAtomType, BoolAtomType],                funcBody = body $ integerAtomFuncLessThan False},@@ -45,31 +62,42 @@                funcBody = body $ integerAtomFuncLessThan True >=> boolAtomNot},     Function { funcName = "not",                funcType = [BoolAtomType, BoolAtomType],-               funcBody = body $ \(b:_) -> boolAtomNot b },+               funcBody = body $ \case+                                         [b] -> boolAtomNot b+                                         _ -> Left AtomFunctionTypeMismatchError+             },     Function { funcName = "int",                funcType = [IntegerAtomType, IntAtomType],                funcBody =-                 body $ \(IntegerAtom v:_) ->-                          if v < fromIntegral (maxBound :: Int) then-                            -                            pure (IntAtom (fromIntegral v))-                          else-                            Left InvalidIntBoundError+                 body $ \case+                                [IntegerAtom v] ->+                                  if v < fromIntegral (maxBound :: Int) then+                                    pure (IntAtom (fromIntegral v))+                                  else+                                    Left InvalidIntBoundError+                                _ -> Left AtomFunctionTypeMismatchError              },     Function { funcName = "integer",                funcType = [IntAtomType, IntegerAtomType],-               funcBody = body $ \(IntAtom v:_) -> Right $ IntegerAtom $ fromIntegral v},+               funcBody = body $ \case+                 [IntAtom v] -> Right $ IntegerAtom $ fromIntegral v+                 _ -> Left AtomFunctionTypeMismatchError+             },     Function { funcName = "uuid",                funcType = [TextAtomType, UUIDAtomType],-               funcBody = body $ \(TextAtom v:_) ->-                 let mUUID = U.fromString (T.unpack v) in-                   case mUUID of-                     Just u -> pure $ UUIDAtom u-                     Nothing -> Left $ InvalidUUIDString v+               funcBody = body $ \case+                 [TextAtom v] ->+                   let mUUID = U.fromString (T.unpack v) in+                     case mUUID of+                       Just u -> pure $ UUIDAtom u+                       Nothing -> Left $ InvalidUUIDString v+                 _ -> Left AtomFunctionTypeMismatchError              }-  ]+  ] <> scientificAtomFunctions   where     body = FunctionBuiltInBody+    relationAtomFunc f [RelationAtom x] = f x+    relationAtomFunc _ _ = Left AtomFunctionTypeMismatchError                           integerAtomFuncLessThan :: Bool -> [Atom] -> Either AtomFunctionError Atom integerAtomFuncLessThan equality (IntegerAtom i1:IntegerAtom i2:_) = pure (BoolAtom (i1 `op` i2))@@ -112,3 +140,44 @@ castInteger :: Atom -> Integer castInteger (IntegerAtom i) = i  castInteger _ = error "attempted to cast non-IntegerAtom to Int"+++scientificAtomFunctions :: AtomFunctions+scientificAtomFunctions = HS.fromList [+  Function { funcName = "read_scientific",+             funcType = [TextAtomType, ScientificAtomType],+             funcBody = body $ \case+               TextAtom t:_ ->+                 case APT.parseOnly (APT.scientific <* APT.endOfInput) t of+                   Left err -> Left (AtomFunctionParseError err)+                   Right sci -> pure (ScientificAtom sci)+               _ -> Left AtomFunctionTypeMismatchError+           },+  Function { funcName = "scientific",+             funcType = [IntegerAtomType, IntAtomType, ScientificAtomType],+             funcBody = body $ \case+               [IntegerAtom c,IntAtom e] -> pure (ScientificAtom $ scientific c e)+               _ -> Left AtomFunctionTypeMismatchError+           },+  Function { funcName = "scientific_add",+             funcType = binaryFuncType,+             funcBody = binaryFuncBody (+)+           },+  Function { funcName = "scientific_subtract",+             funcType = binaryFuncType,+             funcBody = binaryFuncBody (-)+           },+  Function { funcName = "scientific_multiply",+             funcType = binaryFuncType,+             funcBody = binaryFuncBody (*)+           },+  Function { funcName = "scientific_divide",+             funcType = binaryFuncType,+             funcBody = binaryFuncBody (/)+           }+  ]+  where body = FunctionBuiltInBody+        binaryFuncType = [ScientificAtomType, ScientificAtomType, ScientificAtomType]+        binaryFuncBody op = body $ \case+          [ScientificAtom s1, ScientificAtom s2] -> pure (ScientificAtom (s1 `op` s2))+          _ -> Left AtomFunctionTypeMismatchError
src/lib/ProjectM36/AtomType.hs view
@@ -204,10 +204,11 @@  --reconcile the atom-in types with the type constructors isValidAtomTypeForTypeConstructor :: AtomType -> TypeConstructor -> TypeConstructorMapping -> Either RelationalError ()-isValidAtomTypeForTypeConstructor aType (PrimitiveTypeConstructor _ expectedAType) _ = if expectedAType /= aType then Left (AtomTypeMismatchError expectedAType aType) else pure ()+isValidAtomTypeForTypeConstructor aType (PrimitiveTypeConstructor _ expectedAType) _ =+  when (expectedAType /= aType) $ Left (AtomTypeMismatchError expectedAType aType)  --lookup constructor name and check if the incoming atom types are valid-isValidAtomTypeForTypeConstructor (ConstructedAtomType tConsName _) (ADTypeConstructor expectedTConsName _) _ =  if tConsName /= expectedTConsName then Left (TypeConstructorNameMismatch expectedTConsName tConsName) else pure ()+isValidAtomTypeForTypeConstructor (ConstructedAtomType tConsName _) (ADTypeConstructor expectedTConsName _) _ =  when (tConsName /= expectedTConsName) $ Left (TypeConstructorNameMismatch expectedTConsName tConsName)  isValidAtomTypeForTypeConstructor (RelationAtomType attrs) (RelationAtomTypeConstructor attrExprs) tConsMap = do   evaldAtomTypes <- mapM (\expr -> atomTypeForAttributeExpr expr tConsMap M.empty) attrExprs@@ -320,10 +321,7 @@  validateAttributes :: TypeConstructorMapping -> Attributes -> Either RelationalError () validateAttributes tConss attrs =-  if not (null errs) then-    Left (someErrors errs)-  else-    pure ()+  unless (null errs) $ Left (someErrors errs)   where     errs = lefts $ map (`validateAtomType` tConss) (A.atomTypesList attrs) @@ -410,12 +408,15 @@ resolveTypeVariable _ _ = M.empty  resolveFunctionReturnValue :: FunctionName -> TypeVarMap -> AtomType -> Either RelationalError AtomType-resolveFunctionReturnValue funcName' tvMap (ConstructedAtomType tCons retMap) = do-  let diff = M.difference retMap tvMap-  if M.null diff then-    pure (ConstructedAtomType tCons (M.intersection tvMap retMap))-    else-    Left (AtomFunctionTypeVariableResolutionError funcName' (fst (head (M.toList diff))))+resolveFunctionReturnValue funcName' tvMap ctype@(ConstructedAtomType tCons retMap) =+  if isResolvedType ctype then+    pure ctype+    else do+    let diff = M.difference retMap tvMap+    if M.null diff then+      pure (ConstructedAtomType tCons (M.intersection tvMap retMap))+      else+      Left (AtomFunctionTypeVariableResolutionError funcName' (fst (head (M.toList diff)))) resolveFunctionReturnValue funcName' tvMap (TypeVariableType tvName) = case M.lookup tvName tvMap of   Nothing -> Left (AtomFunctionTypeVariableResolutionError funcName' tvName)   Just typ -> pure typ@@ -436,6 +437,7 @@   case typ of     IntAtomType -> True     IntegerAtomType -> True+    ScientificAtomType -> True     DoubleAtomType -> True     TextAtomType -> True     DayAtomType -> True
src/lib/ProjectM36/Atomable.hs view
@@ -241,6 +241,7 @@ typeToTypeConstructor :: AtomType -> TypeConstructor typeToTypeConstructor x@IntAtomType = PrimitiveTypeConstructor "Int" x typeToTypeConstructor x@IntegerAtomType = PrimitiveTypeConstructor "Integer" x+typeToTypeConstructor x@ScientificAtomType = PrimitiveTypeConstructor "Scientific" x typeToTypeConstructor x@DoubleAtomType = PrimitiveTypeConstructor "Double" x typeToTypeConstructor x@TextAtomType = PrimitiveTypeConstructor "Text" x typeToTypeConstructor x@DayAtomType = PrimitiveTypeConstructor "Day" x
src/lib/ProjectM36/Base.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE ExistentialQuantification,DeriveGeneric,DeriveAnyClass,FlexibleInstances,OverloadedStrings, DeriveTraversable, DerivingVia, TemplateHaskell, TypeFamilies #-}+{-# LANGUAGE ExistentialQuantification,DeriveGeneric,DeriveAnyClass,FlexibleInstances,OverloadedStrings, DeriveTraversable, DerivingVia, TemplateHaskell, TypeFamilies, BangPatterns #-} {-# OPTIONS_GHC -fno-warn-orphans #-}  module ProjectM36.Base where@@ -20,12 +20,13 @@ import qualified Data.List as L import Data.Text (Text) import Data.Time.Clock-import Data.Hashable.Time ()+import Data.Time.Clock.Compat () import Data.Time.Calendar (Day) import Data.Typeable import Data.ByteString (ByteString) import qualified Data.List.NonEmpty as NE import Data.Vector.Instances ()+import Data.Scientific  type StringType = Text @@ -44,25 +45,27 @@ #endif  -- | Database atoms are the smallest, undecomposable units of a tuple. Common examples are integers, text, or unique identity keys.-data Atom = IntegerAtom Integer |-            IntAtom Int |-            DoubleAtom Double |-            TextAtom Text |-            DayAtom Day |-            DateTimeAtom UTCTime |-            ByteStringAtom ByteString |-            BoolAtom Bool |-            UUIDAtom UUID |-            RelationAtom Relation |-            RelationalExprAtom RelationalExpr | --used for returning inc deps-            ConstructedAtom DataConstructorName AtomType [Atom]+data Atom = IntegerAtom !Integer |+            IntAtom !Int |+            ScientificAtom !Scientific |+            DoubleAtom !Double |+            TextAtom !Text |+            DayAtom !Day |+            DateTimeAtom !UTCTime |+            ByteStringAtom !ByteString |+            BoolAtom !Bool |+            UUIDAtom !UUID |+            RelationAtom !Relation |+            RelationalExprAtom !RelationalExpr | --used for returning inc deps+            ConstructedAtom !DataConstructorName !AtomType [Atom]             deriving (Eq, Show, Typeable, NFData, Generic, Read)                       instance Hashable Atom where                        hashWithSalt salt (ConstructedAtom dConsName _ atoms) = salt `hashWithSalt` atoms                                                           `hashWithSalt` dConsName --AtomType is not hashable   hashWithSalt salt (IntAtom i) = salt `hashWithSalt` i-  hashWithSalt salt (IntegerAtom i) = salt `hashWithSalt` i  +  hashWithSalt salt (IntegerAtom i) = salt `hashWithSalt` i+  hashWithSalt salt (ScientificAtom s) = salt `hashWithSalt` s   hashWithSalt salt (DoubleAtom d) = salt `hashWithSalt` d   hashWithSalt salt (TextAtom t) = salt `hashWithSalt` t   hashWithSalt salt (DayAtom d) = salt `hashWithSalt` d@@ -77,6 +80,7 @@ -- | The AtomType uniquely identifies the type of a atom. data AtomType = IntAtomType |                 IntegerAtomType |+                ScientificAtomType |                 DoubleAtomType |                 TextAtomType |                 DayAtomType |@@ -102,6 +106,10 @@ isRelationAtomType (RelationAtomType _) = True isRelationAtomType _ = False +-- subrelations sometimes require special paths+attributesContainRelationAtomType :: Attributes -> Bool+attributesContainRelationAtomType attrs = V.null (V.filter (\(Attribute _ t) -> isRelationAtomType t) (attributesVec attrs))+ -- | The AttributeName is the name of an attribute in a relation. type AttributeName = StringType @@ -124,7 +132,9 @@ attributesSet = HS.fromList . V.toList . attributesVec  instance Show Attributes where-  show attrs = "attributesFromList [" <> L.intercalate ", " (map (\attr -> "(" <> show attr <> ")") (V.toList (attributesVec attrs))) <> "]"+  showsPrec d attrs = showString $ parens $ "attributesFromList [" <> L.intercalate ", " (map (\attr -> "(" <> show attr <> ")") (V.toList (attributesVec attrs))) <> "]"+    where parens x | d > 0 = "(" <> x <> ")"+          parens x = x  --when attribute ordering is irrelevant instance Eq Attributes where@@ -136,8 +146,12 @@ sortedAttributesIndices attrs = L.sortBy (\(_, Attribute name1 _) (_,Attribute name2 _) -> compare name1 name2) $ V.toList (V.indexed (attributesVec attrs))  -- | The relation's tuple set is the body of the relation.-newtype RelationTupleSet = RelationTupleSet { asList :: [RelationTuple] } deriving (Hashable, Show, Generic, Read)+newtype RelationTupleSet = RelationTupleSet { asList :: [RelationTuple] } deriving (Show, Generic, Read) +-- we cannot derive Hashable for tuplesets; we need to hash the unordered set of tuples+instance Hashable RelationTupleSet where+  hashWithSalt s tupSet = hashWithSalt s (HS.fromList (asList tupSet))+         instance Read Relation where   readsPrec = error "relation read not supported" @@ -187,7 +201,7 @@ instance Hashable Relation where                                  hashWithSalt salt (Relation attrs tupSet) = salt `hashWithSalt`                                                sortedAttrs `hashWithSalt`-                                              asList tupSet+                                              HS.fromList (asList tupSet)     where       sortedAttrs = map snd (sortedAttributesIndices attrs)       @@ -579,19 +593,20 @@   f1 == f2 = funcName f1 == funcName f2  instance Hashable (Function a) where-  hashWithSalt salt func = salt `hashWithSalt` funcName func `hashWithSalt` funcType func `hashWithSalt` funcBody func-+  hashWithSalt salt func = salt `hashWithSalt` funcName func `hashWithSalt` funcType func `hashWithSalt` hashfuncbody +   where+    hashfuncbody =+      case funcBody func of+        (FunctionScriptBody script _) -> salt `hashWithSalt` script+        (FunctionBuiltInBody _) -> salt+        (FunctionObjectLoadedBody fp modName entryFunc _) -> salt `hashWithSalt` (fp, modName, entryFunc)+   data FunctionBody a =   FunctionScriptBody FunctionBodyScript a |   FunctionBuiltInBody a |   FunctionObjectLoadedBody FilePath ObjectModuleName ObjectFileEntryFunctionName a   deriving Generic -instance Hashable (FunctionBody a) where-  salt `hashWithSalt` (FunctionScriptBody script _) = salt `hashWithSalt` script-  salt `hashWithSalt` (FunctionBuiltInBody _) = salt-  salt `hashWithSalt` (FunctionObjectLoadedBody fp modName entryFunc _) = salt `hashWithSalt` (fp, modName, entryFunc)- instance NFData a => NFData (FunctionBody a) where   rnf (FunctionScriptBody script _) = rnf script   rnf (FunctionBuiltInBody _) = rnf ()@@ -607,6 +622,7 @@ attrTypeVars (Attribute _ aType) = case aType of   IntAtomType -> S.empty   IntegerAtomType -> S.empty+  ScientificAtomType -> S.empty   DoubleAtomType -> S.empty   TextAtomType -> S.empty   DayAtomType -> S.empty@@ -632,6 +648,7 @@ atomTypeVars :: AtomType -> S.Set TypeVarName atomTypeVars IntAtomType = S.empty atomTypeVars IntegerAtomType = S.empty+atomTypeVars ScientificAtomType = S.empty atomTypeVars DoubleAtomType = S.empty atomTypeVars TextAtomType = S.empty atomTypeVars DayAtomType = S.empty
src/lib/ProjectM36/Client.hs view
@@ -290,7 +290,9 @@     [] -> error ("DNS resolution failed for" <> hostName <> ":" <> servicePort)     addrInfo:_ -> do       --supports IPv4 only for now-      let (SockAddrInet port addr) = addrAddress addrInfo+      let (port, addr) = case addrAddress addrInfo of+                           SockAddrInet p a -> (p, a)+                           _ -> error "no IPv4 address available (IPv6 not implemented)"           notificationHandlers =             [RPC.ClientAsyncRequestHandler $              \(NotificationMessage notifications') ->@@ -709,8 +711,8 @@ -- | Write the transaction graph to disk. This function can be used to incrementally write new transactions to disk. processTransactionGraphPersistence :: PersistenceStrategy -> [TransactionId] -> TransactionGraph -> IO () processTransactionGraphPersistence NoPersistence _ _ = pure ()-processTransactionGraphPersistence (MinimalPersistence dbdir) transIds graph = transactionGraphPersist NoDiskSync dbdir transIds graph >> pure ()-processTransactionGraphPersistence (CrashSafePersistence dbdir) transIds graph = transactionGraphPersist FsyncDiskSync dbdir transIds graph >> pure ()+processTransactionGraphPersistence (MinimalPersistence dbdir) transIds graph = void $ transactionGraphPersist NoDiskSync dbdir transIds graph+processTransactionGraphPersistence (CrashSafePersistence dbdir) transIds graph = void $ transactionGraphPersist FsyncDiskSync dbdir transIds graph  readGraphTransactionIdDigest :: PersistenceStrategy -> IO LockFileHash readGraphTransactionIdDigest NoPersistence = error "attempt to read digest from transaction log without persistence enabled"@@ -822,11 +824,7 @@         if Sess.schemaName session == defaultSchemaName then           pure $ RE.relationVariablesAsRelation context graph           else-          case Schema.relationVariablesInSchema schema of-            Left err -> pure (Left err)-            Right relvars -> do-              let schemaContext = context {relationVariables = relvars }-              pure $ RE.relationVariablesAsRelation schemaContext graph +          pure $ Schema.relationVariablesAsRelationInSchema context schema graph        relationVariablesAsRelation sessionId conn@(RemoteConnection _) = remoteCall conn (RetrieveRelationVariableSummary sessionId) 
src/lib/ProjectM36/DataFrame.hs view
@@ -17,6 +17,7 @@ import Data.Maybe import qualified Data.Text as T import Control.Arrow+import Control.Monad (unless) #if __GLASGOW_HASKELL__ < 804 import Data.Monoid #endif@@ -52,10 +53,7 @@ sortDataFrameBy :: [AttributeOrder] -> DataFrame -> Either RelationalError DataFrame sortDataFrameBy attrOrders frame = do   attrs <- mapM (\(AttributeOrder nam _) -> A.attributeForName nam (attributes frame)) attrOrders -  mapM_ (\attr -> if not (isSortableAtomType (atomType attr)) then-            Left (AttributeNotSortableError attr)-            else-            pure ()) attrs+  mapM_ (\attr -> unless (isSortableAtomType (atomType attr)) $ Left (AttributeNotSortableError attr)) attrs   pure $ DataFrame attrOrders (attributes frame) (sortTuplesBy (compareTupleByAttributeOrders attrOrders) (tuples frame))  sortTuplesBy :: (DataFrameTuple -> DataFrameTuple -> Ordering) -> [DataFrameTuple] -> [DataFrameTuple]
src/lib/ProjectM36/DataTypes/ByteString.hs view
@@ -10,9 +10,12 @@ bytestringAtomFunctions = HS.fromList [   Function { funcName = "bytestring",              funcType = [TextAtomType, ByteStringAtomType],-             funcBody = compiledAtomFunctionBody $ \(TextAtom textIn:_) -> case B64.decode (TE.encodeUtf8 textIn) of+             funcBody = compiledAtomFunctionBody $+             \case+               TextAtom textIn:_ -> case B64.decode (TE.encodeUtf8 textIn) of                    Left err -> Left (AtomFunctionBytesDecodingError err)-                   Right bs -> pure (ByteStringAtom bs) +                   Right bs -> pure (ByteStringAtom bs)+               _ -> Left AtomFunctionTypeMismatchError                }   ]        
src/lib/ProjectM36/DataTypes/DateTime.hs view
@@ -1,6 +1,7 @@ module ProjectM36.DataTypes.DateTime where import ProjectM36.Base import ProjectM36.AtomFunctionBody+import ProjectM36.AtomFunctionError import qualified Data.HashSet as HS import Data.Time.Clock.POSIX @@ -8,7 +9,10 @@ dateTimeAtomFunctions = HS.fromList [ Function {                                      funcName = "dateTimeFromEpochSeconds",                                      funcType = [IntegerAtomType, DateTimeAtomType],-                                     funcBody = compiledAtomFunctionBody $ \(IntegerAtom epoch:_) -> pure (DateTimeAtom (posixSecondsToUTCTime (realToFrac epoch)))-                                                                                                       }]+                                     funcBody = compiledAtomFunctionBody $+                                       \case+                                         IntegerAtom epoch:_ -> pure (DateTimeAtom (posixSecondsToUTCTime (realToFrac epoch)))+                                         _ -> Left AtomFunctionTypeMismatchError+                                     }]                                                   
src/lib/ProjectM36/DataTypes/Day.hs view
@@ -1,17 +1,25 @@ module ProjectM36.DataTypes.Day where import ProjectM36.Base import ProjectM36.AtomFunctionBody+import ProjectM36.AtomFunctionError import qualified Data.HashSet as HS import Data.Time.Calendar + dayAtomFunctions :: AtomFunctions dayAtomFunctions = HS.fromList [   Function { funcName = "fromGregorian",                  funcType = [IntegerAtomType, IntegerAtomType, IntegerAtomType, DayAtomType],-                 funcBody = compiledAtomFunctionBody $ \(IntegerAtom year:IntegerAtom month:IntegerAtom day:_) -> pure $ DayAtom (fromGregorian (fromIntegral year) (fromIntegral month) (fromIntegral day))+                 funcBody = compiledAtomFunctionBody $+                            \case+                              IntegerAtom year:IntegerAtom month:IntegerAtom day:_ -> pure $ DayAtom (fromGregorian (fromIntegral year) (fromIntegral month) (fromIntegral day))+                              _ -> Left AtomFunctionTypeMismatchError                  },   Function { funcName = "dayEarlierThan",                  funcType = [DayAtomType, DayAtomType, BoolAtomType],-                 funcBody = compiledAtomFunctionBody $ \(ConstructedAtom _ _ (IntAtom dayA:_):ConstructedAtom _ _ (IntAtom dayB:_):_) -> pure (BoolAtom (dayA < dayB))+                 funcBody = compiledAtomFunctionBody $+                            \case+                              ConstructedAtom _ _ (IntAtom dayA:_):ConstructedAtom _ _ (IntAtom dayB:_):_ -> pure (BoolAtom (dayA < dayB))+                              _ -> Left AtomFunctionTypeMismatchError                }   ]
src/lib/ProjectM36/DataTypes/Either.hs view
@@ -1,6 +1,7 @@ module ProjectM36.DataTypes.Either where import ProjectM36.Base import ProjectM36.AtomFunction+import ProjectM36.AtomFunctionError import qualified Data.HashSet as HS import qualified Data.Map as M        @@ -14,5 +15,7 @@         eitherAtomFunctions :: AtomFunctions                                eitherAtomFunctions = HS.fromList [-  compiledAtomFunction "isLeft" [eitherAtomType (TypeVariableType "a") (TypeVariableType "b"), BoolAtomType] $ \(ConstructedAtom dConsName _ _:_) -> pure (BoolAtom (dConsName == "Left"))+  compiledAtomFunction "isLeft" [eitherAtomType (TypeVariableType "a") (TypeVariableType "b"), BoolAtomType] $ \case+        (ConstructedAtom dConsName _ _:_) -> pure (BoolAtom (dConsName == "Left"))+        _ -> Left AtomFunctionTypeMismatchError   ]
src/lib/ProjectM36/DataTypes/Interval.hs view
@@ -29,6 +29,7 @@ supportsInterval typ = case typ of   IntAtomType -> True   IntegerAtomType -> True+  ScientificAtomType -> True   DoubleAtomType -> True   TextAtomType -> False -- just because it supports ordering, doesn't mean it makes sense in an interval   DayAtomType -> True               @@ -44,7 +45,8 @@ supportsOrdering :: AtomType -> Bool   supportsOrdering typ = case typ of   IntAtomType -> True-  IntegerAtomType -> True  +  IntegerAtomType -> True+  ScientificAtomType -> True   DoubleAtomType -> True   TextAtomType -> True   DayAtomType -> True               @@ -100,20 +102,26 @@                           BoolAtomType,                           BoolAtomType,                           intervalAtomType (TypeVariableType "a")],-             funcBody = compiledAtomFunctionBody $ \(atom1:atom2:BoolAtom bopen:BoolAtom eopen:_) -> do+             funcBody = compiledAtomFunctionBody $+             \case+               (atom1:atom2:BoolAtom bopen:BoolAtom eopen:_) -> do                    let aType = atomTypeForAtom atom1                     if supportsInterval aType then                      createInterval atom1 atom2 bopen eopen                      else                      Left (AtomTypeDoesNotSupportIntervalError (prettyAtomType aType))+               _ -> Left AtomFunctionTypeMismatchError                },   Function {     funcName = "interval_overlaps",     funcType = [intervalAtomType (TypeVariableType "a"),                     intervalAtomType (TypeVariableType "a"),                     BoolAtomType],-    funcBody = compiledAtomFunctionBody $ \(i1@ConstructedAtom{}:i2@ConstructedAtom{}:_) -> -      BoolAtom <$> intervalOverlaps i1 i2+    funcBody = compiledAtomFunctionBody $+      \case+        i1@ConstructedAtom{}:i2@ConstructedAtom{}:_ -> +          BoolAtom <$> intervalOverlaps i1 i2+        _ -> Left AtomFunctionTypeMismatchError     }]                          isIntervalAtomType :: AtomType -> Bool
src/lib/ProjectM36/DataTypes/List.hs view
@@ -37,13 +37,19 @@   Function {      funcName = "length",      funcType = [listAtomType (TypeVariableType "a"), IntAtomType],-     funcBody = FunctionBuiltInBody (\(listAtom:_) ->-                                                 IntAtom . fromIntegral <$> listLength listAtom)+     funcBody = FunctionBuiltInBody $+       \case+               (listAtom:_) ->+                 IntAtom . fromIntegral <$> listLength listAtom+               _ -> Left AtomFunctionTypeMismatchError      },   Function {     funcName = "maybeHead",     funcType = [listAtomType (TypeVariableType "a"), maybeAtomType (TypeVariableType "a")],-    funcBody = FunctionBuiltInBody (\(listAtom:_) -> listMaybeHead listAtom)+    funcBody = FunctionBuiltInBody $+               \case+                 (listAtom:_) -> listMaybeHead listAtom+                 _ -> Left AtomFunctionTypeMismatchError     }   ]                     
src/lib/ProjectM36/DataTypes/Maybe.hs view
@@ -19,12 +19,18 @@   Function {      funcName ="isJust",      funcType = [maybeAtomType (TypeVariableType "a"), BoolAtomType],-     funcBody = FunctionBuiltInBody $ \(ConstructedAtom dConsName _ _:_) -> pure $ BoolAtom (dConsName /= "Nothing")+     funcBody = FunctionBuiltInBody $+       \case+               ConstructedAtom dConsName _ _:_ -> pure $ BoolAtom (dConsName /= "Nothing")+               _ -> Left AtomFunctionTypeMismatchError      },   Function {      funcName = "fromMaybe",      funcType = [TypeVariableType "a", maybeAtomType (TypeVariableType "a"), TypeVariableType "a"],-     funcBody = FunctionBuiltInBody $ \(defaultAtom:ConstructedAtom dConsName _ (atomVal:_):_) -> if atomTypeForAtom defaultAtom /= atomTypeForAtom atomVal then Left AtomFunctionTypeMismatchError else if dConsName == "Nothing" then pure defaultAtom else pure atomVal+     funcBody = FunctionBuiltInBody $+       \case+         (defaultAtom:ConstructedAtom dConsName _ (atomVal:_):_) -> if atomTypeForAtom defaultAtom /= atomTypeForAtom atomVal then Left AtomFunctionTypeMismatchError else if dConsName == "Nothing" then pure defaultAtom else pure atomVal+         _ ->Left AtomFunctionTypeMismatchError               }   ] 
src/lib/ProjectM36/DataTypes/NonEmptyList.hs view
@@ -42,12 +42,18 @@   Function {      funcName = "nonEmptyListLength",      funcType = [nonEmptyListAtomType (TypeVariableType "a"), IntAtomType],-     funcBody = FunctionBuiltInBody (\(nonEmptyListAtom:_) ->-                                                 IntAtom . fromIntegral <$> nonEmptyListLength nonEmptyListAtom)+     funcBody = FunctionBuiltInBody $+       \case+         (nonEmptyListAtom:_) ->+           IntAtom . fromIntegral <$> nonEmptyListLength nonEmptyListAtom+         _ -> Left AtomFunctionTypeMismatchError      },   Function {     funcName = "nonEmptyListHead",     funcType = [nonEmptyListAtomType (TypeVariableType "a"), TypeVariableType "a"],-    funcBody = FunctionBuiltInBody (\(nonEmptyListAtom:_) -> nonEmptyListHead nonEmptyListAtom)+    funcBody = FunctionBuiltInBody $+      \case+        (nonEmptyListAtom:_) -> nonEmptyListHead nonEmptyListAtom+        _ -> Left AtomFunctionTypeMismatchError     }   ]
src/lib/ProjectM36/DataTypes/Primitive.hs view
@@ -2,19 +2,21 @@ import ProjectM36.Base  primitiveTypeConstructorMapping :: TypeConstructorMapping-primitiveTypeConstructorMapping = map (\(name, aType) ->+primitiveTypeConstructorMapping = boolMapping : map (\(name, aType) ->                                   (PrimitiveTypeConstructorDef name aType, [])) prims   where     prims = [("Integer", IntegerAtomType),              ("Int", IntAtomType),              ("Text", TextAtomType),              ("Double", DoubleAtomType),-             ("Bool", BoolAtomType),              ("UUID", UUIDAtomType),              ("ByteString", ByteStringAtomType),              ("DateTime", DateTimeAtomType),              ("Day", DayAtomType)             ]+    boolMapping = (PrimitiveTypeConstructorDef "Bool" BoolAtomType,+                   [DataConstructorDef "True" [],+                    DataConstructorDef "False" []])              intTypeConstructor :: TypeConstructor             intTypeConstructor = PrimitiveTypeConstructor "Int" IntAtomType@@ -38,6 +40,7 @@ atomTypeForAtom :: Atom -> AtomType atomTypeForAtom (IntAtom _) = IntAtomType atomTypeForAtom (IntegerAtom _) = IntegerAtomType+atomTypeForAtom (ScientificAtom _) = ScientificAtomType atomTypeForAtom (DoubleAtom _) = DoubleAtomType atomTypeForAtom (TextAtom _) = TextAtomType atomTypeForAtom (DayAtom _) = DayAtomType
src/lib/ProjectM36/DataTypes/Sorting.hs view
@@ -5,6 +5,7 @@ compareAtoms (IntegerAtom i1) (IntegerAtom i2) = compare i1 i2 compareAtoms (IntAtom i1) (IntAtom i2) = compare i1 i2 compareAtoms (DoubleAtom d1) (DoubleAtom d2) = compare d1 d2+compareAtoms (ScientificAtom s1) (ScientificAtom s2) = compare s1 s2 compareAtoms (TextAtom t1) (TextAtom t2) = compare t1 t2 compareAtoms (DayAtom d1) (DayAtom d2) = compare d1 d2 compareAtoms (DateTimeAtom d1) (DateTimeAtom d2) = compare d1 d2@@ -20,6 +21,7 @@   IntAtomType -> True   IntegerAtomType -> True   DoubleAtomType -> True+  ScientificAtomType -> True   TextAtomType -> True   DayAtomType -> True   DateTimeAtomType -> True
src/lib/ProjectM36/IsomorphicSchema.hs view
@@ -12,9 +12,13 @@ import qualified Data.Map as M import qualified Data.Set as S import qualified Data.List as L+import qualified Data.Vector as V+import qualified ProjectM36.Attribute as A+import ProjectM36.AtomType #if __GLASGOW_HASKELL__ < 804 import Data.Monoid #endif+ -- isomorphic schemas offer bi-directional functors between two schemas  --TODO: note that renaming a relvar should alter any stored isomorphisms as well@@ -79,9 +83,10 @@  -- | Check that all mentioned relvars are actually present in the current schema. validateRelationalExprInSchema :: Schema -> RelationalExpr -> Either RelationalError ()-validateRelationalExprInSchema schema relExprIn = relExprMogrify (\case-                                                                     RelationVariable rv () | S.notMember rv validRelVarNames -> Left (RelVarNotDefinedError rv)-                                                                     ex -> Right ex) relExprIn >> pure ()+validateRelationalExprInSchema schema relExprIn =+  void $ relExprMogrify (\case+                            RelationVariable rv () | S.notMember rv validRelVarNames -> Left (RelVarNotDefinedError rv)+                            ex -> Right ex) relExprIn   where     validRelVarNames = isomorphsInRelVarNames (isomorphs schema)   @@ -93,7 +98,7 @@   foldM processRelExpr relExprIn (isomorphs schema)    validateDatabaseContextExprInSchema :: Schema -> DatabaseContextExpr -> Either RelationalError ()  -validateDatabaseContextExprInSchema schema dbExpr = mapM_ (\morph -> databaseContextExprMorph morph (\e -> validateRelationalExprInSchema schema e >> pure e) dbExpr) (isomorphs schema) >> pure ()+validateDatabaseContextExprInSchema schema dbExpr = mapM_ (\morph -> databaseContextExprMorph morph (\e -> validateRelationalExprInSchema schema e >> pure e) dbExpr) (isomorphs schema)    processDatabaseContextExprInSchema :: Schema -> DatabaseContextExpr -> Either RelationalError DatabaseContextExpr   processDatabaseContextExprInSchema schema@(Schema morphs) dbExpr = do@@ -265,6 +270,24 @@       pure (M.union newRvMap (M.fromList rvAssocs))  +-- | Show metadata about the relation variables in the isomorphic schema.+relationVariablesAsRelationInSchema :: DatabaseContext -> Schema -> TransactionGraph -> Either RelationalError Relation+relationVariablesAsRelationInSchema concreteDbContext schema graph = do+  rvDefsInConcreteSchema <- relationVariablesInSchema schema+  let gfEnv = freshGraphRefRelationalExprEnv (Just concreteDbContext) graph+  typAssocs <- forM (M.toList rvDefsInConcreteSchema) $ \(rv, gfExpr) -> do+    typ <- runGraphRefRelationalExprM gfEnv (typeForGraphRefRelationalExpr gfExpr)+    pure (rv, typ)+  let tups = map relVarToAtomList typAssocs+      subrelAttrs = A.attributesFromList [Attribute "attribute" TextAtomType, Attribute "type" TextAtomType]+      attrs = A.attributesFromList [Attribute "name" TextAtomType,+                                  Attribute "attributes" (RelationAtomType subrelAttrs)]+      relVarToAtomList (rvName, rel) = [TextAtom rvName, attributesToRel (attributesVec (attributes rel))]+      attrAtoms a = [TextAtom (A.attributeName a), TextAtom (prettyAtomType (A.atomType a))]  +      attributesToRel attrl = case mkRelationFromList subrelAttrs (map attrAtoms (V.toList attrl)) of+        Left err -> error ("relationVariablesAsRelation pooped " ++ show err)+        Right rel -> RelationAtom rel+  mkRelationFromList attrs tups  {- proposal
src/lib/ProjectM36/Persist.hs view
@@ -1,13 +1,14 @@ {-# LANGUAGE ForeignFunctionInterface, CPP #-} --this module is related to persisting Project:M36 structures to disk and not related to the persistent library module ProjectM36.Persist (writeFileSync, -                           writeBSFileSync,+                           writeSerialiseSync,                            renameSync,                            printFdCount,                            DiskSync(..)) where -- on Windows, use FlushFileBuffers and MoveFileEx import qualified Data.Text as T-+import Codec.Winery+import qualified Data.ByteString.FastBuilder as BB #if defined(linux_HOST_OS) # define FDCOUNTSUPPORTED 1 # define FDDIR "/proc/self/fd"@@ -35,8 +36,8 @@ import Foreign.C #endif -import System.IO (withFile, IOMode(WriteMode), Handle)-import qualified Data.ByteString as BS'+import System.IO (withFile, IOMode(WriteMode), Handle, withBinaryFile)+import qualified Data.ByteString as BS import qualified Data.Text.Encoding as TE  #if defined(mingw32_HOST_OS)@@ -52,7 +53,7 @@ writeFileSync sync path strOut = withFile path WriteMode handler   where     handler handle = do-      BS'.hPut handle (TE.encodeUtf8 strOut)+      BS.hPut handle (TE.encodeUtf8 strOut)       syncHandle sync handle  renameSync :: DiskSync -> FilePath -> FilePath -> IO ()@@ -99,10 +100,11 @@ syncDirectory FsyncDiskSync path = directoryFsync path  syncDirectory NoDiskSync _ = pure () -writeBSFileSync :: DiskSync -> FilePath -> BS'.ByteString -> IO ()-writeBSFileSync sync path bstring =-  withFile path WriteMode $ \handle -> do-    BS'.hPut handle bstring+--uses lazy bytestring to write to file+writeSerialiseSync :: Serialise a => DiskSync -> FilePath -> a -> IO ()+writeSerialiseSync sync path val = +  withBinaryFile path WriteMode $ \handle -> do+    BB.hPutBuilder handle $ toBuilderWithSchema val     syncHandle sync handle    directoryFsync :: FilePath -> IO ()
src/lib/ProjectM36/Relation/Parse/CSV.hs view
@@ -60,6 +60,7 @@ parseCSVAtomP :: AttributeName -> TypeConstructorMapping -> AtomType -> APT.Parser (Either RelationalError Atom) parseCSVAtomP _ _ IntegerAtomType = Right . IntegerAtom <$> APT.decimal parseCSVAtomP _ _ IntAtomType = Right . IntAtom <$> APT.decimal+parseCSVAtomP _ _ ScientificAtomType = Right . ScientificAtom <$> APT.scientific parseCSVAtomP _ _ DoubleAtomType = Right . DoubleAtom <$> APT.double parseCSVAtomP _ _ TextAtomType =    Right . TextAtom <$> (quotedString <|> takeToEndOfData)
src/lib/ProjectM36/RelationalExpression.hs view
@@ -862,6 +862,9 @@   let gfEnv = mergeTuplesIntoGraphRefRelationalExprEnv tupIn env   relAtom <- lift $ except $ runGraphRefRelationalExprM gfEnv (evalGraphRefRelationalExpr relExpr)   pure (RelationAtom relAtom)+evalGraphRefAtomExpr _ (ConstructedAtomExpr tOrF [] _)+  | tOrF == "True" = pure (BoolAtom True)+  | tOrF == "False" = pure (BoolAtom False) evalGraphRefAtomExpr tupIn cons@(ConstructedAtomExpr dConsName dConsArgs _) = do --why is the tid unused here? suspicious   let mergeEnv = mergeTuplesIntoGraphRefRelationalExprEnv tupIn   aType <- local mergeEnv (typeForGraphRefAtomExpr (tupleAttributes tupIn) cons)@@ -893,15 +896,27 @@     Right func -> do       let funcRetType = last (funcType func)           funcArgTypes = init (funcType func)+          funArgCount = length funcArgTypes+          inArgCount = length atomArgs+      when (funArgCount /= inArgCount) (throwError (FunctionArgumentCountMismatchError funArgCount inArgCount))       argTypes <- mapM (typeForGraphRefAtomExpr attrs) atomArgs+      mapM_ (\(fArg,arg,argCount) -> do+                let handler :: RelationalError -> GraphRefRelationalExprM AtomType+                    handler (AtomTypeMismatchError expSubType actSubType) = throwError (AtomFunctionTypeError funcName' argCount expSubType actSubType)+                    handler err = throwError err+                lift (except $ atomTypeVerify fArg arg) `catchError` handler+            ) (zip3 funcArgTypes argTypes [1..])       let eTvMap = resolveTypeVariables funcArgTypes argTypes       case eTvMap of             Left err -> throwError err-            Right tvMap -> lift $ except $ resolveFunctionReturnValue funcName' tvMap funcRetType+            Right tvMap ->+              lift $ except $ resolveFunctionReturnValue funcName' tvMap funcRetType typeForGraphRefAtomExpr attrs (RelationAtomExpr relExpr) = do   relType <- R.local (mergeAttributesIntoGraphRefRelationalExprEnv attrs) (typeForGraphRefRelationalExpr relExpr)   pure (RelationAtomType (attributes relType)) -- grab the type of the data constructor, then validate that the args match the expected types+typeForGraphRefAtomExpr _ (ConstructedAtomExpr tOrF [] _) | tOrF `elem` ["True", "False"] =+                                                            pure BoolAtomType typeForGraphRefAtomExpr attrs (ConstructedAtomExpr dConsName dConsArgs tid) =   do     argsTypes <- mapM (typeForGraphRefAtomExpr attrs) dConsArgs
src/lib/ProjectM36/ScriptSession.hs view
@@ -19,30 +19,47 @@ import Data.Maybe import GHC.Paths (libdir) import System.Environment-#if __GLASGOW_HASKELL__ >= 800-import GHC.LanguageExtensions-import GHCi.ObjLink-#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)+import GHC.LanguageExtensions (Extension(OverloadedStrings,ExtendedDefaultRules,ImplicitPrelude,ScopedTypeVariables))++#if MIN_VERSION_ghc(9,2,0)+-- GHC 9.2.2+import GHC.Utils.Panic (handleGhcException)+import GHC.Driver.Session (projectVersion, PackageDBFlag(PackageDB), PkgDbRef(PkgDbPath), TrustFlag(TrustPackage), gopt_set, xopt_set, PackageFlag(ExposePackage), PackageArg(PackageArg), ModRenaming(ModRenaming))+import GHC.Types.SourceText (SourceText(NoSourceText))+import GHC.Unit.Types (IsBootInterface(NotBoot))+import GHC.Driver.Ppr (showSDocForUser)+import GHC.Core.Type (eqType)+import GHC.Types.TyThing.Ppr (pprTypeForUser)+import GHC.Utils.Encoding (zEncodeString)+import GHC.Unit.State (emptyUnitState)+#elif MIN_VERSION_ghc(9,0,0)+-- GHC 9.0.0+import GHC.Utils.Panic (handleGhcException)+import GHC.Driver.Session (projectVersion, PackageDBFlag(PackageDB), PkgDbRef(PkgDbPath), TrustFlag(TrustPackage), gopt_set, xopt_set, PackageFlag(ExposePackage), PackageArg(PackageArg), ModRenaming(ModRenaming))+import GHC.Types.Basic (SourceText(NoSourceText))+import GHC.Unit.Types (IsBootInterface(NotBoot))+import GHC.Core.Type (eqType)+import GHC.Utils.Outputable (showSDocForUser)+import GHC.Utils.Encoding (zEncodeString)+import GHC.Core.Ppr.TyThing (pprTypeForUser) #else+-- GHC 8.10.7+import BasicTypes (SourceText(NoSourceText))+import Outputable (showSDocForUser)+import PprTyThing (pprTypeForUser)+import Type (eqType)+import Encoding (zEncodeString)+import Panic (handleGhcException)+import DynFlags (projectVersion, PkgConfRef(PkgConfFile), TrustFlag(TrustPackage), gopt_set, xopt_set, PackageFlag(ExposePackage), PackageArg(PackageArg), ModRenaming(ModRenaming), PackageDBFlag(PackageDB)) #endif+ import GHC.Exts (addrToAny#) import GHC.Ptr (Ptr(..))-import Encoding+import GHCi.ObjLink (initObjLinker, ShouldRetainCAFs(RetainCAFs), resolveObjs, lookupSymbol, loadDLL, loadObj) #endif+-- endif for SCRIPTING FLAG  data ScriptSession = ScriptSession { #ifdef PM36_HASKELL_SCRIPTING@@ -90,33 +107,35 @@       homeDir </> ".stack/snapshots/*/*/" ++ ghcVersion ++ "/pkgdb"       --homeDir </> ".cabal/store/ghc-" ++ ghcVersion ++ "/package.db"       ]--    let localPkgPaths = map PkgConfFile (ghcPkgPaths ++ sandboxPkgPaths ++ maybeToList mNixLibDir)+#if MIN_VERSION_ghc(9,0,0)+    let pkgConf = PkgDbPath+#else+    let pkgConf = PkgConfFile+#endif+    let localPkgPaths = map pkgConf (ghcPkgPaths ++ sandboxPkgPaths ++ maybeToList mNixLibDir) -    let dflags' = applyGopts . applyXopts $ dflags { hscTarget = HscInterpreted ,+    let dflags' = applyGopts . applyXopts $ dflags {+#if MIN_VERSION_ghc(9,2,0)+                           backend = Interpreter,+#else  +                           hscTarget = HscInterpreted ,+#endif                            ghcLink = LinkInMemory,                            safeHaskell = Sf_Trustworthy,                            safeInfer = True,                            safeInferred = True,                            --verbosity = 3,-#if __GLASGOW_HASKELL__ >= 800+                            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 -                         }+--                           extraPkgConfs = const (localPkgPaths ++ [UserPkgConf, GlobalPkgConf])+        }+         applyGopts flags = foldl gopt_set flags gopts         applyXopts flags = foldl xopt_set flags xopts-#if __GLASGOW_HASKELL__ >= 800         xopts = [OverloadedStrings, ExtendedDefaultRules, ImplicitPrelude, ScopedTypeVariables]-#else-        xopts = [Opt_OverloadedStrings, Opt_ExtendedDefaultRules, Opt_ImplicitPrelude,  Opt_ScopedTypeVariables]-#endif         gopts = [] --[Opt_DistrustAllPackages, Opt_PackageTrust]         required_packages = ["base",                              "containers",@@ -131,42 +150,42 @@                              "time",                              "project-m36",                              "bytestring"]-#if __GLASGOW_HASKELL__ >= 800         packages = map (\m -> ExposePackage ("-package " ++ m) (PackageArg m) (ModRenaming True [])) required_packages-#else-        packages = map TrustPackage required_packages-#endif   --liftIO $ traceShowM (showSDoc dflags' (ppr packages))     _ <- setSessionDynFlags dflags'-    let safeImportDecl mn mQual = ImportDecl {-#if __GLASGOW_HASKELL__ >= 802+    let safeImportDecl :: String -> Maybe String -> ImportDecl (GhcPass 'Parsed)+        safeImportDecl fullModuleName mQualifiedName = ImportDecl {           ideclSourceSrc = NoSourceText,-#else-          ideclSourceSrc = Nothing,-#endif -#if __GLASGOW_HASKELL__ >= 810+#if MIN_VERSION_ghc(9,2,0)+          ideclExt = noAnn,+#else           ideclExt = noExtField,-#elif __GLASGOW_HASKELL__ >= 806-          ideclExt = NoExt, #endif-          ideclName      = noLoc mn,+#if MIN_VERSION_ghc(9,2,0)+          --GenLocated SrcSpanAnnA ModuleName+          ideclName      = noLocA (mkModuleName fullModuleName),+#else+          ideclName      = noLoc (mkModuleName fullModuleName),+#endif           ideclPkgQual   = Nothing,+#if MIN_VERSION_ghc(9,0,0)+          ideclSource    = NotBoot,+#else           ideclSource    = False,+#endif+           ideclSafe      = True,           ideclImplicit  = False,-#if __GLASGOW_HASKELL__ >= 810-          ideclQualified = if isJust mQual then QualifiedPre else NotQualified,+          ideclQualified = if isJust mQualifiedName then QualifiedPre else NotQualified,+#if MIN_VERSION_ghc(9,2,0)+          ideclAs        = Just (noLocA (mkModuleName fullModuleName)), #else-          ideclQualified = isJust mQual,+          ideclAs        = noLoc . mkModuleName <$> mQualifiedName, #endif-          ideclAs        = mQual,           ideclHiding    = Nothing           }-#if __GLASGOW_HASKELL__ >= 806-          :: ImportDecl (GhcPass (c :: Pass))-#endif-        unqualifiedModules = map (\modn -> IIDecl $ safeImportDecl (mkModuleName modn) Nothing) [+        unqualifiedModules = map (\modn -> IIDecl $ safeImportDecl modn Nothing) [           "Prelude",           "Data.Map",           "Data.Either",@@ -178,12 +197,7 @@           "ProjectM36.DatabaseContextFunctionError",           "ProjectM36.DatabaseContextFunctionUtils",           "ProjectM36.RelationalExpression"]-#if __GLASGOW_HASKELL__ >= 802-        mkModName = noLoc . mkModuleName-#else-        mkModName = mkModuleName-#endif-        qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl (mkModuleName modn) (Just (mkModName qualNam))) [+        qualifiedModules = map (\(modn, qualNam) -> IIDecl $ safeImportDecl modn (Just qualNam)) [           ("Data.Text", "T")           ]     setContext (unqualifiedModules ++ qualifiedModules)@@ -198,7 +212,11 @@   setContext (IIDecl (simpleImportDecl (mkModuleName moduleNam)) : ctx)  showType :: DynFlags -> Type -> String+#if MIN_VERSION_ghc(9,2,0)+showType dflags ty = showSDocForUser dflags emptyUnitState alwaysQualify (pprTypeForUser ty)+#else showType dflags ty = showSDocForUser dflags alwaysQualify (pprTypeForUser ty)+#endif  mkTypeForName :: String -> Ghc Type mkTypeForName name = do@@ -231,11 +249,7 @@ 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@@ -271,11 +285,7 @@  loadFunction :: ObjectLoadMode -> ModName -> FuncName -> FilePath -> IO (Either LoadSymbolError a) loadFunction loadMode modName funcName objPath = do-#if __GLASGOW_HASKELL__ >= 802   initObjLinker RetainCAFs-#else-  initObjLinker-#endif   let loadFuncForSymbol = do             _ <- resolveObjs         ptr <- lookupSymbol (mangleSymbol Nothing modName funcName)
src/lib/ProjectM36/Serialise/Base.hs view
@@ -11,9 +11,12 @@ import Data.Proxy import Data.Word import ProjectM36.Attribute as A-import qualified Data.List.NonEmpty as NE import qualified Data.Vector as V import Data.Time.Calendar (Day,toGregorian,fromGregorian)+#if MIN_VERSION_winery(1,4,0)+#else+import qualified Data.List.NonEmpty as NE+#endif  deriving via WineryVariant Atom instance Serialise Atom deriving via WineryVariant AtomType instance Serialise AtomType@@ -55,6 +58,8 @@   extractor = fromWordsTup <$> extractor   decodeCurrent = fromWordsTup <$> decodeCurrent +#if MIN_VERSION_winery(1,4,0)+#else instance Serialise a => Serialise (NE.NonEmpty a) where   schemaGen _ = SVector <$> getSchema (Proxy @a)   toBuilder xs = varInt (length xs) <> foldMap toBuilder xs@@ -63,6 +68,7 @@     n <- decodeVarInt     l <- replicateM n decodeCurrent     pure (NE.fromList l)+#endif  fromGregorianTup :: (Integer, Int, Int) -> Day fromGregorianTup (a, b, c) = fromGregorian a b c
src/lib/ProjectM36/StaticOptimizer.hs view
@@ -525,7 +525,10 @@           optFinalExpr = case finalExpr of                               Restrict _ subexpr -> applyStaticRestrictionCollapse subexpr                               otherExpr -> otherExpr-          andPreds = foldr (\(Restrict subpred _) acc -> AndPredicate acc subpred) firstPred (tail restrictions) in+          andPreds = foldr folder firstPred (tail restrictions)+          folder (Restrict subpred _) acc = AndPredicate acc subpred+          folder _ _ = error "unexpected restriction expression in optimization phase"+      in       Restrict andPreds optFinalExpr        sequentialRestrictions :: RelationalExprBase a -> [RelationalExprBase a]
+ src/lib/ProjectM36/Trace.hs view
@@ -0,0 +1,10 @@+module ProjectM36.Trace where+import Debug.Trace (traceEventIO)+-- utility module to enable easy enabling/disabling of eventlog data++-- | Utility function for tracing with ghc-events-analyze using START and STOP markers+traceBlock :: String -> IO () -> IO ()+traceBlock label m = do+  traceEventIO ("START " <> label)+  m+  traceEventIO ("STOP " <> label)
src/lib/ProjectM36/Transaction/Persist.hs view
@@ -1,16 +1,18 @@ {-# LANGUAGE DerivingVia #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE CPP #-} #ifdef PM36_HASKELL_SCRIPTING {-# LANGUAGE TypeApplications #-} #endif module ProjectM36.Transaction.Persist where+import ProjectM36.Trace import ProjectM36.Base import ProjectM36.Error import ProjectM36.Transaction import ProjectM36.DatabaseContextFunction import ProjectM36.AtomFunction-import ProjectM36.Persist (writeBSFileSync, DiskSync, renameSync)+import ProjectM36.Persist (DiskSync, renameSync, writeSerialiseSync) import ProjectM36.Function import qualified Data.Map as M import qualified Data.HashSet as HS@@ -109,14 +111,14 @@ writeRelVars :: DiskSync -> FilePath -> RelationVariables -> IO () writeRelVars sync transDir relvars = do   let path = relvarsPath transDir-  writeBSFileSync sync path (serialise relvars)+  traceBlock "write relvars" $ writeSerialiseSync sync path relvars  readRelVars :: FilePath -> IO RelationVariables readRelVars transDir =    readFileDeserialise (relvarsPath transDir)  writeFuncs :: Traversable t => DiskSync -> FilePath -> t (Function a) -> IO ()-writeFuncs sync funcWritePath funcs = do+writeFuncs sync funcWritePath funcs = traceBlock "write functions" $ do   funcs' <- forM funcs $ \fun -> do     case funcBody fun of       FunctionScriptBody{} -> pure fun@@ -134,7 +136,7 @@             Just (ObjectFileInfo (objPath, modName, entryFunc))           FunctionScriptBody{} -> Nothing           FunctionBuiltInBody{} -> Nothing-  writeBSFileSync sync funcWritePath (serialise $ fmap functionData (toList funcs'))+  writeSerialiseSync sync funcWritePath (fmap functionData (toList funcs'))  readFuncs :: FilePath -> FilePath -> HS.HashSet (Function a) -> Maybe ScriptSession -> IO (HS.HashSet (Function a)) readFuncs transDir funcPath precompiledFunctions mScriptSession = do@@ -223,11 +225,12 @@ #endif  writeIncDep :: DiskSync -> FilePath -> (IncDepName, InclusionDependency) -> IO ()  -writeIncDep sync transDir (incDepName, incDep) = -  writeBSFileSync sync (incDepsDir transDir </> T.unpack incDepName) $ serialise incDep+writeIncDep sync transDir (incDepName, incDep) = do+  writeSerialiseSync sync (incDepsDir transDir </> T.unpack incDepName) incDep    writeIncDeps :: DiskSync -> FilePath -> M.Map IncDepName InclusionDependency -> IO ()  -writeIncDeps sync transDir incdeps = mapM_ (writeIncDep sync transDir) $ M.toList incdeps +writeIncDeps sync transDir incdeps = +  traceBlock "write incdeps" $ mapM_ (writeIncDep sync transDir) $ M.toList incdeps     readIncDep :: FilePath -> IncDepName -> IO (IncDepName, InclusionDependency) readIncDep transDir incdepName = do@@ -249,11 +252,12 @@ writeSubschemas :: DiskSync -> FilePath -> Subschemas -> IO ()   writeSubschemas sync transDir sschemas = do   let sschemasPath = subschemasPath transDir-  writeBSFileSync sync sschemasPath (serialise sschemas)+  traceBlock "write subschemas" $ writeSerialiseSync sync sschemasPath sschemas    writeTypeConstructorMapping :: DiskSync -> FilePath -> TypeConstructorMapping -> IO ()  -writeTypeConstructorMapping sync path types = let atPath = typeConsPath path in-  writeBSFileSync sync atPath $ serialise types+writeTypeConstructorMapping sync path types = do+  let atPath = typeConsPath path+  traceBlock "write tconsmap" $ writeSerialiseSync sync atPath types  readTypeConstructorMapping :: FilePath -> IO TypeConstructorMapping readTypeConstructorMapping path = do
src/lib/ProjectM36/TransactionGraph.hs view
@@ -621,10 +621,8 @@  validateMerkleHash :: Transaction -> TransactionGraph -> Either MerkleValidationError () validateMerkleHash trans graph = -  if expectedHash /= actualHash  then+  when (expectedHash /= actualHash) $     Left (MerkleValidationError (transactionId trans) expectedHash actualHash)-  else-    pure ()   where     expectedHash = merkleHash (transactionInfo trans)     actualHash = calculateMerkleHash trans graph
src/lib/ProjectM36/TransactionGraph/Merge.hs view
@@ -8,6 +8,7 @@ import qualified Data.Map as M import qualified ProjectM36.TypeConstructorDef as TCD import qualified Data.HashSet as HS+import qualified Data.Text as T  data MergePreference = PreferFirst | PreferSecond | PreferNeither @@ -69,7 +70,7 @@             let findType tcm = case filter (\(t,_) -> TCD.name t == name) tcm of                   [] -> Nothing                   [x] -> Just x-                  _ -> error "multiple names matching in TypeConstructorMapping"+                  _ -> error $ "multiple names matching in TypeConstructorMapping for " <> T.unpack name                 lookupA = findType typesA                 lookupB = findType typesB                 cat t = pure (t : acc)
src/lib/ProjectM36/TransactionGraph/Persist.hs view
@@ -32,6 +32,7 @@ import Data.Time.Clock import Data.Text.Read import System.FilePath.Glob+import Data.Tuple  type LockFileHash = ByteString @@ -143,14 +144,21 @@         headsStrLines = map headFileStr $ M.toList (transactionHeadsForGraph graph)     writeFileSync sync tempHeadsPath $ T.intercalate "\n" headsStrLines     renameSync sync tempHeadsPath (headsPath dbdir)-                                                             + transactionGraphHeadsLoad :: FilePath -> IO [(HeadName,TransactionId)] transactionGraphHeadsLoad dbdir = do   headsData <- readFile (headsPath dbdir)-  let headsAssocs = map (\l -> let [headName, uuidStr] = words l in-                          (headName,uuidStr)-                          ) (lines headsData)+  let headsAssocs = map twowords (lines headsData)   return [(T.pack headName, uuid) | (headName, Just uuid) <- map (second U.fromString) headsAssocs]++data Pos = One | Two++twowords :: String -> (String, String)+twowords s = swap $ snd $ foldr twowordfolder (One, ("","")) s+  where+    twowordfolder ' ' (One, acc) = (Two,acc)+    twowordfolder c (One, (a, b)) =  (One, (c:a, b))+    twowordfolder c (Two, (a, b)) = (Two, (a, c:b))    {-   load any transactions which are not already part of the incoming transaction graph@@ -212,7 +220,10 @@ readGraphTransactionIdFile :: FilePath -> IO (Either PersistenceError [(TransactionId, UTCTime, [TransactionId])]) readGraphTransactionIdFile dbdir = do   --read in all transactions' uuids-  let grapher line = let tid:epochText:parentIds' = T.words line in+  let grapher line = let (tid,epochText,parentIds') = case T.words line of+                           x:y:zs -> (x,y,zs)+                           _ -> error "failed to parse transaction id file"+                           in         (readUUID tid, readEpoch epochText, map readUUID parentIds')       readUUID uuidText = fromMaybe (error "failed to read uuid") (U.fromText uuidText)       readEpoch t = posixSecondsToUTCTime (realToFrac (either (error "failed to read epoch") fst (double t)))@@ -228,4 +239,5 @@       case TE.decodeUtf8' fileBytes of         Left err -> error (show err)         Right utf8Bytes -> pure utf8Bytes+ 
test/IsomorphicSchema.hs view
@@ -7,10 +7,11 @@ import ProjectM36.TransactionGraph import ProjectM36.StaticOptimizer import qualified ProjectM36.DatabaseContext as DBC-import qualified ProjectM36.Attribute as A+import ProjectM36.Attribute (attributesFromList) import System.Exit import qualified Data.Map as M import qualified Data.Set as S+import qualified Data.Vector as V  testList :: Test testList = TestList [testIsoRename, testIsoRestrict, testIsoUnion, testSchemaValidation]@@ -67,7 +68,7 @@ testIsoRestrict = TestCase $ do   -- create a emp relation which is restricted into two boss, nonboss rel vars   -- the virtual schema has an employee-  let empattrs = A.attributesFromList [Attribute "name" TextAtomType,+  let empattrs = attributesFromList [Attribute "name" TextAtomType,                                         Attribute "boss" TextAtomType]   (graph, transId) <- freshTransactionGraph DBC.empty                    emprel <- assertEither $ mkRelationFromList empattrs@@ -85,6 +86,7 @@                                         ("boss", ExistingRelation bossRel)]         }       isomorphsAtoB = [IsoRestrict "employee" predicate ("boss", "nonboss")]+      schemaB = Schema isomorphsAtoB       bossq = RelationVariable "boss" ()       nonbossq = RelationVariable "nonboss" ()       employeeq = RelationVariable "employee" ()@@ -108,13 +110,24 @@   processedExpr <- assertEither (processRelationalExprInSchema (Schema isomorphsAtoB) (RelationVariable "employee" ()))   let processedRel = runRelationalExprM postInsertEnv (evalRelationalExpr processedExpr)   assertEqual "insert bob boss" expectedRel processedRel++  -- test that we can render isomorphic schema metadata+  let rvTypes = relationVariablesAsRelationInSchema baseContext schemaB graph+      rvattrs = attributesFromList [Attribute "name" TextAtomType, Attribute "attributes" (RelationAtomType subrelattrs)]+      subrelattrs = attributesFromList [Attribute "attribute" TextAtomType, Attribute "type" TextAtomType]+      expectedTypes = mkRelationFromList rvattrs +        [[TextAtom "employee",+           RelationAtom (Relation subrelattrs+                          (RelationTupleSet [RelationTuple subrelattrs (V.fromList [TextAtom "boss",TextAtom "Text"]),+                                             RelationTuple subrelattrs (V.fromList [TextAtom "name",TextAtom "Text"])]))]]+  assertEqual "relationVariablesAsRelationInSchema" expectedTypes rvTypes    testIsoUnion :: Test   testIsoUnion = TestCase $ do   --create motors relation which is split into low-power (<50 horsepower) and high-power (>=50 horsepower) motors   --the schema is contains the split relvars   (graph, _) <- freshTransactionGraph DBC.empty-  motorsRel <- assertEither $ mkRelationFromList (A.attributesFromList [Attribute "name" TextAtomType,+  motorsRel <- assertEither $ mkRelationFromList (attributesFromList [Attribute "name" TextAtomType,                                                                         Attribute "power" IntegerAtomType])                 [[TextAtom "Puny", IntegerAtom 10],                 [TextAtom "Scooter", IntegerAtom 49],@@ -136,3 +149,4 @@   highpowerRel <- assertEither (relResult highpowerExpr)   assertEqual "lowpower relation difference" (Right lowpowerRel) lowmotors   assertEqual "highpower relation difference" (Right highpowerRel) highmotors+
test/Relation/Basic.hs view
@@ -7,12 +7,14 @@ import ProjectM36.RelationalExpression import ProjectM36.TransactionGraph import ProjectM36.Tuple+import ProjectM36.Attribute (attributesFromList) import qualified ProjectM36.DatabaseContext as DBC import qualified ProjectM36.Attribute as A import qualified Data.Map as M import qualified Data.Vector as V import qualified Data.Set as S import System.Exit+import Data.Hashable (hashWithSalt)   testList :: Test@@ -24,7 +26,8 @@                      testRelation "supplierProducts" supplierProductsRel,                      testMkRelationFromExprsBadAttrs,                      testExistingRelationType,-                     testReorderTuple+                     testReorderTuple,+                     testRelationEquality                     ]  main :: IO ()           @@ -117,3 +120,27 @@       actual = reorderTuple attrs2 tup1       expected = mkRelationTuple attrs2 (V.fromList [TextAtom "test", IntAtom 4])   assertEqual "reorderTuple" expected actual++testRelationEquality :: Test+testRelationEquality = TestCase $ do+  -- relations with changed orders of tuples must hash to the same value and be equal, even in lieu of subrelations+  let r1 = Relation rattrs $ RelationTupleSet {asList = [RelationTuple subrelattrs+                                                        (V.fromList [RelationAtom subrel1])]+                                             }+      rattrs = attributesFromList [Attribute "x" (RelationAtomType subrelattrs)]++      r2 = Relation rattrs $ RelationTupleSet {asList = [RelationTuple subrelattrs+                                 (V.fromList [RelationAtom subrel2])]+                      }+      subrelattrs = attributesFromList [Attribute "y" IntAtomType]           +      subrel1 = Relation subrelattrs tupset1+      tupset1 = RelationTupleSet [RelationTuple subrelattrs (V.fromList [IntAtom 3]),+                                RelationTuple subrelattrs (V.fromList [IntAtom 4])]+      subrel2 = Relation subrelattrs tupset2+      tupset2 = RelationTupleSet [RelationTuple subrelattrs (V.fromList [IntAtom 4]),+                                  RelationTuple subrelattrs (V.fromList [IntAtom 3])]++  assertEqual "relation eq" r1 r2+  assertEqual "relation hash" (hashWithSalt 0 r1) (hashWithSalt 0 r2)+  assertEqual "tupset eq" tupset1 tupset2+  assertEqual "tupset hash" (hashWithSalt 0 tupset1) (hashWithSalt 0 tupset2)
test/Server/Main.hs view
@@ -19,6 +19,7 @@ import Control.Exception import System.IO.Temp import System.FilePath+import Control.Monad (void) #if defined(linux_HOST_OS) import System.Directory #endif@@ -89,7 +90,7 @@                                          checkFS = False --not stricly needed for these tests                                        }     -      launchServer config (Just addressMVar) >> pure ()+      void $ launchServer config (Just addressMVar)   (SockAddrInet port _) <- takeMVar addressMVar   --liftIO $ putStrLn ("launched server on " ++ show endPointAddress)   pure (fromIntegral port, tid)
test/Server/WebSocket.hs view
@@ -18,6 +18,7 @@ import qualified Data.Map as M import qualified Data.ByteString.Lazy as BS import ProjectM36.Relation+import Control.Monad (void)  --start the websocket server -- run some tutoriald against it@@ -30,7 +31,7 @@                                      checkFS = False}       testDatabaseName = "test"   -- start normal server-  _ <- forkIO (launchServer config (Just addressMVar) >> pure ())+  void $ forkIO (void $ launchServer config (Just addressMVar))   (SockAddrInet dbPort _) <- takeMVar addressMVar   let wsServerHost = "127.0.0.1"       wsServerPort = 8889
test/TutorialD/InterpreterTest.hs view
@@ -29,12 +29,13 @@ import Data.Text.Encoding as TE import Control.Concurrent import qualified Data.Set as S-import Data.Text hiding (map)+import Data.Text (unpack, Text) import qualified Data.Text as T import Data.Time.Clock.POSIX hiding (getCurrentTime) import Data.Time.Clock (getCurrentTime) import Data.Time.Calendar (fromGregorian) import Data.Either+import Data.Scientific  main :: IO () main = do@@ -84,7 +85,8 @@       testSelfReferencingUncommittedContext,       testUnionAndIntersectionAttributeExprs,       testUndefineConstraints,-      testQuotedRelVarNames      +      testQuotedRelVarNames,+      testScientific       ]  simpleRelTests :: Test@@ -113,8 +115,10 @@                       ("x:=true where false or false", Right relationFalse),                       ("x:=true where true and false", Right relationFalse),                       ("x:=true where false and true", Right relationFalse),                      -                      ("x:=true where ^t and ^f", Right relationFalse),+                      ("x:=true where True and False", Right relationFalse),                       ("x:=true where true and true", Right relationTrue),+                      ("x:=true where true and True", Right relationTrue),+                      ("x:=true where True and true", Right relationTrue), -- flip these around to catch parser bugs                       ("x:=true=true", Right relationTrue),                       ("x:=true=false", Right relationFalse),                       ("x:=true; undefine x", Left (RelVarNotDefinedError "x")),@@ -175,11 +179,11 @@                            ("x:=((sp{s#,qty}) group ({qty} as x):{z:=min(@x)}){s#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [TextAtom s,IntegerAtom i]) [("S1", 100), ("S2", 300), ("S3", 200), ("S4", 200)])),                            ("x:=((sp{s#,qty}) group ({qty} as x):{z:=sum(@x)}){s#,z}", mkRelationFromList minMaxAttrs (map (\(s,i) -> [TextAtom s,IntegerAtom i]) [("S1", 1000), ("S2", 700), ("S3", 200), ("S4", 900)])),                            --boolean function restriction-                           ("x:=s where ^lt(@status,20)", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S2", TextAtom "Jones", IntegerAtom 10, TextAtom "Paris"]]),-                           ("x:=s where ^gt(@status,20)", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S3", TextAtom "Blake", IntegerAtom 30, TextAtom "Paris"],+                           ("x:=s where lt(@status,20)", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S2", TextAtom "Jones", IntegerAtom 10, TextAtom "Paris"]]),+                           ("x:=s where gt(@status,20)", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S3", TextAtom "Blake", IntegerAtom 30, TextAtom "Paris"],                                                                                                        [TextAtom "S5", TextAtom "Adams", IntegerAtom 30, TextAtom "Athens"]]),-                           ("x:=s where ^sum(@status)", Left $ AtomTypeMismatchError IntegerAtomType BoolAtomType),-                           ("x:=s where ^not(gte(@status,20))", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S2", TextAtom "Jones", IntegerAtom 10, TextAtom "Paris"]]),+                           ("x:=s where sum(@status)", Left $ AtomFunctionTypeError "sum" 1 (RelationAtomType (attributesFromList [Attribute "_" IntegerAtomType])) IntegerAtomType),+                           ("x:=s where not(gte(@status,20))", mkRelationFromList (R.attributes suppliersRel) [[TextAtom "S2", TextAtom "Jones", IntegerAtom 10, TextAtom "Paris"]]),                            --test "all but" attribute inversion syntax                            ("x:=s{all but s#} = s{city,sname,status}", Right relationTrue),                            --test key syntax@@ -430,7 +434,7 @@ testSchemaExpr = TestCase $ do   (sessionId, dbconn) <- dateExamplesConnection emptyNotificationCallback     mapM_ (executeTutorialD sessionId dbconn) [-    ":addschema test (isopassthrough \"true\", isopassthrough \"false\", isorename \"supplier\" \"s\", isorename \"supplier_product\" \"sp\", isounion \"heavy_product\" \"light_product\" \"p\" ^gte(17,@weight))",+    ":addschema test (isopassthrough \"true\", isopassthrough \"false\", isorename \"supplier\" \"s\", isorename \"supplier_product\" \"sp\", isounion \"heavy_product\" \"light_product\" \"p\" gte(17,@weight))",     ":setschema test",     ""     ]@@ -524,12 +528,12 @@ testIntervalAtom = TestCase $ do     --test interval creation   (sessionId, dbconn) <- dateExamplesConnection emptyNotificationCallback  -  executeTutorialD sessionId dbconn "x:=relation{tuple{n 1, a interval(3,4,f,f), b interval(4,5,f,f)}, tuple{n 2,a interval(3,4,t,t), b interval(4,5,t,t)}}"+  executeTutorialD sessionId dbconn "x:=relation{tuple{n 1, a interval(3,4,False,False), b interval(4,5,False,False)}, tuple{n 2,a interval(3,4,True,True), b interval(4,5,True,True)}}"   --test failed interval creation   let err1 = "AtomFunctionUserError InvalidIntervalOrderingError"       err2 = "AtomFunctionUserError (AtomTypeDoesNotSupportIntervalError \"Text\")"-  expectTutorialDErr sessionId dbconn (T.isPrefixOf err1) "z:=relation{tuple{a interval(4,3,f,f)}}"-  expectTutorialDErr sessionId dbconn (T.isPrefixOf err2) "z:=relation{tuple{a interval(\"s\",\"t\",f,f)}}"  +  expectTutorialDErr sessionId dbconn (T.isPrefixOf err1) "z:=relation{tuple{a interval(4,3,False,False)}}"+  expectTutorialDErr sessionId dbconn (T.isPrefixOf err2) "z:=relation{tuple{a interval(\"s\",\"t\",False,False)}}"      --test interval_overlaps   executeTutorialD sessionId dbconn "y:=x:{c:=interval_overlaps(@a,@b)}"@@ -681,12 +685,12 @@ testAtomFunctionArgumentMismatch :: Test testAtomFunctionArgumentMismatch = TestCase $ do   (sessionId, dbconn) <- dateExamplesConnection emptyNotificationCallback-  let err1 = "AtomTypeMismatchError"+  let err1 = "AtomFunctionTypeError"   --atom function type mismatch-  expectTutorialDErr sessionId dbconn (T.isPrefixOf err1) "x:=relation{tuple{a 5}} where ^gt(@a,1.5)"+  expectTutorialDErr sessionId dbconn (T.isPrefixOf err1) "x:=relation{tuple{a 5}} where gt(@a,1.5)"   --wrong argument count   let err2 = "FunctionArgumentCountMismatchError"-  expectTutorialDErr sessionId dbconn (T.isPrefixOf err2) "x:=relation{tuple{a 5}} where ^gt(@a,1,3)"+  expectTutorialDErr sessionId dbconn (T.isPrefixOf err2) "x:=relation{tuple{a 5}} where gt(@a,1,3)"  testInvalidDataConstructor :: Test testInvalidDataConstructor = TestCase $ do@@ -751,3 +755,17 @@   let qAttrExpected = Right (Assign "test" (MakeRelationFromExprs Nothing (TupleExprs () [TupleExpr (M.singleton "\28450\23383" (NakedAtomExpr (TextAtom "test")))])))   assertEqual "quoted attribute" qAttrExpected (parseDBExpr "test:=relation{tuple{`漢字` \"test\"}}")   assertBool "invalid quoted rv" (isLeft (parseDBExpr "`TEST:=true"))++testScientific :: Test+testScientific = TestCase $ do+  (sessionId, dbconn) <- dateExamplesConnection emptyNotificationCallback+  let getX = executeRelationalExpr sessionId dbconn (RelationVariable "x" ())+  executeTutorialD sessionId dbconn "x:=relation{tuple{a scientific(1,int(100))}}"+  createSciRel <- getX+  let expectedRel = mkRelationFromList attrs [[ScientificAtom (scientific 1 100)]]+      attrs = attributesFromList [Attribute "a" ScientificAtomType]+  assertEqual "scientific creation" expectedRel createSciRel+  --test some math functions+  executeTutorialD sessionId dbconn "x:=relation{tuple{a scientific_add(scientific(2,int(100)),scientific(1,int(100)))}}"+  addSciRel <- getX+  assertEqual "scientific add" (mkRelationFromList attrs [[ScientificAtom (scientific 3 100)]]) addSciRel
test/TutorialD/PrinterTest.hs view
@@ -16,7 +16,7 @@   testPretty "true:{a:=1, b:=1}" (Extend (AttributeExtendTupleExpr "b" (NakedAtomExpr (IntegerAtom 1))) (Extend (AttributeExtendTupleExpr "a" (NakedAtomExpr (IntegerAtom 1))) (RelationVariable "true" ()))),   testPretty "relation{tuple{a fromGregorian(2014, 2, 4)}}" (MakeRelationFromExprs Nothing (TupleExprs () [TupleExpr (fromList [("a",FunctionAtomExpr "fromGregorian" [NakedAtomExpr (IntegerAtom 2014),NakedAtomExpr (IntegerAtom 2),NakedAtomExpr (IntegerAtom 4)] ())])])),   testPretty "relation{tuple{a bytestring(\"dGVzdGRhdGE=\")}}" (MakeRelationFromExprs Nothing (TupleExprs () [TupleExpr (fromList [("a",FunctionAtomExpr "bytestring" [NakedAtomExpr (TextAtom "dGVzdGRhdGE=")] ())])])),-  testPretty "relation{tuple{a t}}" (MakeRelationFromExprs Nothing (TupleExprs () [TupleExpr (fromList [("a",NakedAtomExpr (BoolAtom True))])])),+  testPretty "relation{tuple{a True}}" (MakeRelationFromExprs Nothing (TupleExprs () [TupleExpr (fromList [("a",ConstructedAtomExpr "True" [] ())])])),   testPretty "relation{tuple{a Cons 4 (Cons 5 Empty)}}" (MakeRelationFromExprs Nothing (TupleExprs () [TupleExpr (fromList [("a",ConstructedAtomExpr "Cons" [NakedAtomExpr (IntegerAtom 4),ConstructedAtomExpr "Cons" [NakedAtomExpr (IntegerAtom 5),ConstructedAtomExpr "Empty" [] ()] ()] ())])])),   testPretty "relation{a Int, b Text, c Bool}{}" (MakeRelationFromExprs (Just [AttributeAndTypeNameExpr "a" (ADTypeConstructor "Int" []) (),AttributeAndTypeNameExpr "b" (ADTypeConstructor "Text" []) (),AttributeAndTypeNameExpr "c" (ADTypeConstructor "Bool" []) ()]) (TupleExprs () [])),   testPretty "relation{a relation{b Int}}{}" (MakeRelationFromExprs (Just [AttributeAndTypeNameExpr "a" (RelationAtomTypeConstructor [AttributeAndTypeNameExpr "b" (ADTypeConstructor "Int" []) ()]) ()]) (TupleExprs () []))