on master help sign in
move dataframe creation and sorting to server-side via Client.hs

add preliminary test

commite9f102334de7462e1a7171c776c7884781ded53e authorAgentM <agentm@themactionfaction.com> dateSat 5 Jan 2019, 00:02 (8 years ago) parentd4d1df8
17 files changed+262−55
project-m36.cabal+10−1 runghcid.sh+1−1 src/bin/TutorialD/Interpreter/Base.hs+9−2 src/bin/TutorialD/Interpreter/RODatabaseContextOperator.hs+15−33 src/lib/ProjectM36/Attribute.hs+4 src/lib/ProjectM36/Client.hs+33−1 src/lib/ProjectM36/DataFrame.hs+108 src/lib/ProjectM36/DataTypes/Sorting.hs+30 src/lib/ProjectM36/Error.hs+2−1 src/lib/ProjectM36/Relation/Show/Term.hs−10 src/lib/ProjectM36/Server.hs+1 src/lib/ProjectM36/Server/EntryPoints.hs+7−1 src/lib/ProjectM36/Server/RemoteCallTypes.hs+4−1 src/lib/ProjectM36/Tuple.hs+2−2 test/DataFrame.hs+34 test/Relation/Basic.hs+1−1 test/TutorialD/Interpreter.hs+1−1
project-m36.cabal+10−1
@@ -77,6 +77,7 @@ Library
7777 ProjectM36.Tupleable,
7878 ProjectM36.DataConstructorDef,
7979 ProjectM36.DataTypes.Basic,
80+ ProjectM36.DataTypes.Sorting,
8081 ProjectM36.DataTypes.Day,
8182 ProjectM36.DataTypes.DateTime,
8283 ProjectM36.DataTypes.Either,
@@ -504,4 +505,12 @@ Executable handles
504505 if flag(profiler)
505506 GHC-Prof-Options: -fprof-auto -rtsopts -threaded -Wall
506507
507−
508+Test-Suite test-dataframe
509+ Default-Language: Haskell2010
510+ Main-Is: test/DataFrame.hs
511+ type: exitcode-stdio-1.0
512+ Other-Modules: 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.SchemaOperator, TutorialD.Interpreter.TestBase, TutorialD.Interpreter.TransGraphRelationalOperator, TutorialD.Interpreter.TransactionGraphOperator, TutorialD.Interpreter.Types
513+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics, binary, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, websockets, optparse-applicative, network, aeson, project-m36, random, MonadRandom, semigroups
514+ Default-Extensions: OverloadedStrings
515+ GHC-Options: -Wall -threaded
516+ Hs-Source-Dirs: ./src/bin, ., test/
runghcid.sh+1−1
@@ -1,2 +1,2 @@
11#!/bin/sh
2−./.cabal-sandbox/bin/ghcid --command="cabal repl $1"
2+~/.cabal/bin/ghcid --command="cabal new-repl $1"
src/bin/TutorialD/Interpreter/Base.hs+9−2
@@ -13,6 +13,7 @@ module TutorialD.Interpreter.Base (
1313import ProjectM36.Base
1414import ProjectM36.AtomType
1515import ProjectM36.Relation
16+import ProjectM36.DataFrame
1617
1718#if MIN_VERSION_megaparsec(6,0,0)
1819import Text.Megaparsec.Char
@@ -59,8 +60,7 @@ displayOpResult (DisplayParseErrorResult mPromptLength err) = do
5960 pointyString len = T.justifyRight (len + fromIntegral errorIndent) '_' "^"
6061 maybe (pure ()) (TIO.putStrLn . pointyString) mPromptLength
6162 TIO.putStr ("ERR:" <> errString)
62−displayOpResult (DisplayDataFrameResult dFrame) = do
63− TIO.putStrLn (showRelation $ fromDataFrame dFrame)
63+displayOpResult (DisplayDataFrameResult dFrame) = TIO.putStrLn (showDataFrame dFrame)
6464
6565#if MIN_VERSION_megaparsec(6,0,0)
6666type Parser = Parsec Void Text
@@ -126,6 +126,13 @@ integer = Lex.signed spaceConsumer Lex.decimal
126126integer = Lex.signed spaceConsumer Lex.integer
127127#endif
128128
129+natural :: Parser Integer
130+#if MIN_VERSION_megaparsec(6,0,0)
131+natural = Lex.decimal <* spaceConsumer
132+#else
133+natural = Lex.integer <* spaceConsumer
134+#endif
135+
129136float :: Parser Double
130137float = Lex.float
131138
src/bin/TutorialD/Interpreter/RODatabaseContextOperator.hs+15−33
@@ -1,9 +1,7 @@
11{-# LANGUAGE GADTs #-}
22module TutorialD.Interpreter.RODatabaseContextOperator where
33import ProjectM36.Base
4−import ProjectM36.Attribute (attributeForName)
5−import ProjectM36.DataFrame
6−import ProjectM36.Relation (attributes)
4+import qualified ProjectM36.DataFrame as DF
75import ProjectM36.Error
86import ProjectM36.InclusionDependency
97import qualified ProjectM36.Client as C
@@ -27,7 +25,7 @@ data RODatabaseContextOperator where
2725 ShowRelationVariables :: RODatabaseContextOperator
2826 ShowAtomFunctions :: RODatabaseContextOperator
2927 ShowDatabaseContextFunctions :: RODatabaseContextOperator
30− ShowDataFrame :: RelationalExpr -> [AttributeOrderExpr] -> Maybe Integer -> Maybe Integer -> RODatabaseContextOperator
28+ ShowDataFrame :: DF.DataFrameExpr -> RODatabaseContextOperator
3129 Quit :: RODatabaseContextOperator
3230 deriving (Show)
3331
@@ -151,27 +149,11 @@ evalRODatabaseContextOp sessionId conn ShowDatabaseContextFunctions = do
151149 Left err -> pure $ DisplayErrorResult (T.pack (show err))
152150 Right rel -> evalRODatabaseContextOp sessionId conn (ShowRelation (ExistingRelation rel))
153151
154−evalRODatabaseContextOp sessionId conn (ShowDataFrame expr attrOrdersExpr mbOffset mbLimit) = do
155− res <- C.executeRelationalExpr sessionId conn expr
156− case res of
157− Left err -> pure $ DisplayErrorResult $ T.pack (show err)
158− Right rel -> do
159− let relAttrs = attributes rel
160− attrName (AttributeOrderExpr name _) = name
161− order (AttributeOrderExpr _ ord) = ord
162− orders = map order attrOrdersExpr
163− attributeForName' = flip attributeForName relAttrs
164− attrNames = map attrName attrOrdersExpr
165− verified = forM attrNames attributeForName'
166− case verified of
167− Left err -> pure $ DisplayErrorResult $ T.pack (show err)
168− Right attrs -> do
169− let attrOrders = map (\(attr',order')->AttributeOrder attr' order') (zip attrs orders)
170− let dFrame = sortDataFrameBy attrOrders . toDataFrame $ rel
171− let dFrame' = maybe dFrame (`drop'` dFrame) mbOffset
172− let dFrame'' = maybe dFrame' (`take'` dFrame') mbLimit
173− pure $ DisplayDataFrameResult $ dFrame''
174−
152+evalRODatabaseContextOp sessionId conn (ShowDataFrame dfExpr) = do
153+ eDataFrame <- C.executeDataFrameExpr sessionId conn dfExpr
154+ case eDataFrame of
155+ Left err -> pure (DisplayErrorResult (T.pack (show err)))
156+ Right dframe -> pure (DisplayDataFrameResult dframe)
175157
176158evalRODatabaseContextOp _ _ Quit = pure QuitResult
177159
@@ -188,24 +170,24 @@ showDataFrameP = do
188170 attrOrdersExpr <- attrOrdersExprP
189171 mbOffset <- optional offsetP
190172 mbLimit <- optional limitP
191− pure $ ShowDataFrame relExpr attrOrdersExpr mbOffset mbLimit
173+ pure $ ShowDataFrame (DF.DataFrameExpr relExpr attrOrdersExpr mbOffset mbLimit)
192174
193175
194176offsetP :: Parser Integer
195177offsetP = do
196178 reservedOp "offset"
197− integer
179+ natural
198180
199181limitP :: Parser Integer
200182limitP = do
201183 reservedOp "limit"
202− integer
184+ natural
203185
204−attrOrdersExprP :: Parser [AttributeOrderExpr]
186+attrOrdersExprP :: Parser [DF.AttributeOrderExpr]
205187attrOrdersExprP = braces (sepBy attrOrderExprP comma)
206188
207−attrOrderExprP :: Parser AttributeOrderExpr
208−attrOrderExprP = AttributeOrderExpr <$> identifier <*> orderP
189+attrOrderExprP :: Parser DF.AttributeOrderExpr
190+attrOrderExprP = DF.AttributeOrderExpr <$> identifier <*> orderP
209191
210−orderP :: Parser Order
211−orderP = (try $ reservedOp "ASC" >> pure ASC) <|> (try $ reservedOp "DESC" >> pure DESC) <|> pure ASC
192+orderP :: Parser DF.Order
193+orderP = try (reservedOp "ascending" >> pure DF.AscendingOrder) <|> try (reservedOp "descending" >> pure DF.DescendingOrder) <|> pure DF.AscendingOrder
src/lib/ProjectM36/Attribute.hs+4
@@ -7,6 +7,7 @@ import qualified Data.Vector as V
77import qualified Data.Hashable as Hash
88import qualified Data.HashSet as HS
99import qualified Data.Map as M
10+import Data.Either
1011
1112arity :: Attributes -> Int
1213arity = V.length
@@ -74,6 +75,9 @@ attributeForName attrName attrs = case V.find (\attr -> attributeName attr == at
7475 Nothing -> Left (NoSuchAttributeNamesError (S.singleton attrName))
7576 Just attr -> Right attr
7677
78+isAttributeNameContained :: AttributeName -> Attributes -> Bool
79+isAttributeNameContained nam attrs = isRight (attributeForName nam attrs)
80+
7781--similar to attributesForNames, but returns error if some names are missing
7882projectionAttributesForNames :: S.Set AttributeName -> Attributes -> Either RelationalError Attributes
7983projectionAttributesForNames names attrsIn =
src/lib/ProjectM36/Client.hs+33−1
@@ -16,7 +16,8 @@ module ProjectM36.Client
1616 closeRemote_,
1717 executeRelationalExpr,
1818 executeDatabaseContextExpr,
19− executeDatabaseContextIOExpr,
19+ executeDatabaseContextIOExpr,
20+ executeDataFrameExpr,
2021 executeGraphExpr,
2122 executeSchemaExpr,
2223 executeTransGraphRelationalExpr,
@@ -86,6 +87,10 @@ module ProjectM36.Client
8687 IncDepName,
8788 InclusionDependency(..),
8889 AttributeName,
90+ DF.DataFrame(..),
91+ DF.DataFrameExpr(..),
92+ DF.AttributeOrderExpr(..),
93+ DF.Order(..),
8994 RelationalError(..),
9095 RequestTimeoutException(..),
9196 RemoteProcessDiedException(..),
@@ -103,6 +108,7 @@ import ProjectM36.Atomable
103108import ProjectM36.AtomFunction as AF
104109import ProjectM36.StaticOptimizer
105110import ProjectM36.Key
111+import qualified ProjectM36.DataFrame as DF
106112import ProjectM36.DatabaseContextFunction as DCF
107113import qualified ProjectM36.IsomorphicSchema as Schema
108114import Control.Monad.State
@@ -1137,3 +1143,29 @@ withTransaction sessionId conn io successFunc = bracketOnError (pure ()) (const
11371143 Right _ -> pure (Right val)
11381144 else -- no updates executed, so don't create a commit
11391145 pure (Right val)
1146+
1147+executeDataFrameExpr :: SessionId -> Connection -> DF.DataFrameExpr -> IO (Either RelationalError DF.DataFrame)
1148+executeDataFrameExpr sessionId conn@(InProcessConnection _) dfExpr = do
1149+ eRel <- executeRelationalExpr sessionId conn (DF.convertExpr dfExpr)
1150+ case eRel of
1151+ Left err -> pure (Left err)
1152+ Right rel -> do
1153+ let relAttrs = R.attributes rel
1154+ attrName (DF.AttributeOrderExpr name _) = name
1155+ order (DF.AttributeOrderExpr _ ord) = ord
1156+ orders = map order (DF.orderExprs dfExpr)
1157+ attributeForName' = flip attributeForName relAttrs
1158+ attrNames = map attrName (DF.orderExprs dfExpr)
1159+ verified = forM attrNames attributeForName'
1160+ case verified of
1161+ Left err -> pure (Left err)
1162+ Right attrs -> do
1163+ let attrOrders = map (\(attr',order') -> DF.AttributeOrder (attributeName attr') order') (zip attrs orders)
1164+ case DF.sortDataFrameBy attrOrders . DF.toDataFrame $ rel of
1165+ Left err -> pure (Left err)
1166+ Right dFrame -> do
1167+ let dFrame' = maybe dFrame (`DF.drop'` dFrame) (DF.offset dfExpr)
1168+ dFrame'' = maybe dFrame' (`DF.take'` dFrame') (DF.limit dfExpr)
1169+ pure (Right dFrame'')
1170+executeDataFrameExpr sessionId conn@(RemoteProcessConnection _) dfExpr = remoteCall conn (ExecuteDataFrameExpr sessionId dfExpr)
1171+
src/lib/ProjectM36/DataFrame.hsnew file+108
@@ -0,0 +1,108 @@
1+{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}
2+{- A dataframe is a strongly-typed, ordered list of named tuples. A dataframe differs from a relation in that its tuples are ordered.-}
3+module ProjectM36.DataFrame where
4+import ProjectM36.Base
5+import ProjectM36.Attribute as A
6+import ProjectM36.Error
7+import qualified ProjectM36.Relation as R
8+import ProjectM36.Relation.Show.Term
9+import ProjectM36.DataTypes.Sorting
10+import ProjectM36.AtomType
11+import qualified Data.Vector as V
12+import GHC.Generics
13+import qualified Data.List as L
14+import qualified Data.Set as S
15+import Data.Maybe
16+import qualified Data.Text as T
17+import Data.Binary
18+
19+data AttributeOrderExpr = AttributeOrderExpr AttributeName Order deriving (Show, Generic, Binary)
20+data AttributeOrder = AttributeOrder AttributeName Order deriving (Show, Generic, Binary)
21+data Order = AscendingOrder | DescendingOrder deriving (Eq, Show, Generic, Binary)
22+
23+data DataFrame = DataFrame Attributes [DataFrameTuple] deriving (Show, Generic, Binary)
24+
25+data DataFrameTuple = DataFrameTuple Attributes (V.Vector Atom) deriving (Eq, Show, Generic, Binary)
26+
27+attributes :: DataFrame -> Attributes
28+attributes (DataFrame attrs _) = attrs
29+
30+tuples :: DataFrame -> [DataFrameTuple]
31+tuples (DataFrame _ tups) = tups
32+
33+sortDataFrameBy :: [AttributeOrder] -> DataFrame -> Either RelationalError DataFrame
34+sortDataFrameBy attrOrders frame = do
35+ attrs <- mapM (\(AttributeOrder nam _) -> A.attributeForName nam (attributes frame)) attrOrders
36+ mapM_ (\attr -> if not (isSortableAtomType (atomType attr)) then
37+ Left (AttributeNotSortableError attr)
38+ else
39+ pure ()) attrs
40+ pure $ DataFrame (attributes frame) (sortTuplesBy (compareTupleByAttributeOrders attrOrders) (tuples frame))
41+
42+sortTuplesBy :: (DataFrameTuple -> DataFrameTuple -> Ordering) -> [DataFrameTuple] -> [DataFrameTuple]
43+sortTuplesBy = L.sortBy
44+
45+compareTupleByAttributeOrders :: [AttributeOrder] -> DataFrameTuple -> DataFrameTuple -> Ordering
46+compareTupleByAttributeOrders attributeOrders tup1 tup2 =
47+ let compare' (AttributeOrder attr order) = if order == DescendingOrder
48+ then compareTupleByOneAttributeName attr tup2 tup1
49+ else compareTupleByOneAttributeName attr tup1 tup2
50+ res = map compare' attributeOrders in
51+ fromMaybe EQ (L.find (/= EQ) res)
52+
53+compareTupleByOneAttributeName :: AttributeName -> DataFrameTuple -> DataFrameTuple -> Ordering
54+compareTupleByOneAttributeName attr tuple1 tuple2 =
55+ let eAtom1 = atomForAttributeName attr tuple1
56+ eAtom2 = atomForAttributeName attr tuple2 in
57+ case eAtom1 of
58+ Left err -> error (show err)
59+ Right atom1 ->
60+ case eAtom2 of
61+ Left err -> error (show err)
62+ Right atom2 -> compareAtoms atom1 atom2
63+
64+atomForAttributeName :: AttributeName -> DataFrameTuple -> Either RelationalError Atom
65+atomForAttributeName attrName (DataFrameTuple tupAttrs tupVec) = case V.findIndex (\attr -> attributeName attr == attrName) tupAttrs of
66+ Nothing -> Left (NoSuchAttributeNamesError (S.singleton attrName))
67+ Just index -> case tupVec V.!? index of
68+ Nothing -> Left (NoSuchAttributeNamesError (S.singleton attrName))
69+ Just atom -> Right atom
70+
71+take' :: Integer -> DataFrame -> DataFrame
72+take' n (DataFrame attrs tuples') = DataFrame attrs (take (fromInteger n) tuples')
73+
74+drop' :: Integer -> DataFrame -> DataFrame
75+drop' n (DataFrame attrs tuples') = DataFrame attrs (drop (fromInteger n) tuples')
76+
77+toDataFrame :: Relation -> DataFrame
78+toDataFrame (Relation attrs (RelationTupleSet tuples')) = DataFrame attrs (map (\(RelationTuple tupAttrs tupVec) -> DataFrameTuple tupAttrs tupVec) tuples')
79+
80+fromDataFrame :: DataFrame -> Either RelationalError Relation
81+fromDataFrame (DataFrame attrs dftuples) = R.mkRelation attrs (RelationTupleSet tuples')
82+ where
83+ tuples' = map (\(DataFrameTuple attrs' tupVec) -> RelationTuple attrs' tupVec) dftuples
84+
85+--terminal display
86+dataFrameAsTable :: DataFrame -> Table
87+dataFrameAsTable (DataFrame attrs tups) = (header, body)
88+ where
89+ oAttrNames = orderedAttributeNames attrs
90+ oAttrs = orderedAttributes attrs
91+ header = "DF" : map prettyAttribute oAttrs
92+ body = snd (L.foldl' tupleFolder (1 :: Int,[]) tups)
93+ tupleFolder (count, acc) tuple = (count + 1,
94+ acc ++ [T.pack (show count) : map (\attrName -> case atomForAttributeName attrName tuple of
95+ Left _ -> "?"
96+ Right atom -> showAtom 0 atom
97+ ) oAttrNames])
98+
99+showDataFrame :: DataFrame -> StringType
100+showDataFrame = renderTable . dataFrameAsTable
101+
102+-- | A Relation can be converted to a DataFrame for sorting, limits, and offsets.
103+data DataFrameExpr = DataFrameExpr {
104+ convertExpr :: RelationalExpr,
105+ orderExprs :: [AttributeOrderExpr],
106+ offset :: Maybe Integer,
107+ limit :: Maybe Integer
108+ } deriving (Show, Binary, Generic)
src/lib/ProjectM36/DataTypes/Sorting.hsnew file+30
@@ -0,0 +1,30 @@
1+module ProjectM36.DataTypes.Sorting where
2+import ProjectM36.Base
3+
4+compareAtoms :: Atom -> Atom -> Ordering
5+compareAtoms (IntegerAtom i1) (IntegerAtom i2) = compare i1 i2
6+compareAtoms (IntAtom i1) (IntAtom i2) = compare i1 i2
7+compareAtoms (DoubleAtom d1) (DoubleAtom d2) = compare d1 d2
8+compareAtoms (TextAtom t1) (TextAtom t2) = compare t1 t2
9+compareAtoms (DayAtom d1) (DayAtom d2) = compare d1 d2
10+compareAtoms (DateTimeAtom d1) (DateTimeAtom d2) = compare d1 d2
11+compareAtoms (ByteStringAtom b1) (ByteStringAtom b2) = compare b1 b2
12+compareAtoms (BoolAtom b1) (BoolAtom b2) = compare b1 b2
13+compareAtoms (RelationAtom _) _ = EQ
14+compareAtoms ConstructedAtom{} _ = EQ
15+compareAtoms _ _ = EQ
16+
17+isSortableAtomType :: AtomType -> Bool
18+isSortableAtomType typ = case typ of
19+ IntAtomType -> True
20+ IntegerAtomType -> True
21+ DoubleAtomType -> True
22+ TextAtomType -> True
23+ DayAtomType -> True
24+ DateTimeAtomType -> True
25+ ByteStringAtomType -> False
26+ BoolAtomType -> True
27+ RelationAtomType _ -> False
28+ ConstructedAtomType _ _ -> False
29+ TypeVariableType _ -> False
30+
src/lib/ProjectM36/Error.hs+2−1
@@ -62,6 +62,7 @@ data RelationalError = NoSuchAttributeNamesError (S.Set AttributeName)
6262 | AtomTypeNameInUseError AtomTypeName
6363 | IncompletelyDefinedAtomTypeWithConstructorError
6464 | AtomTypeNameNotInUseError AtomTypeName
65+ | AttributeNotSortableError Attribute
6566 | FunctionNameInUseError AtomFunctionName
6667 | FunctionNameNotInUseError AtomFunctionName
6768 | EmptyCommitError
@@ -141,4 +142,4 @@ data SchemaError = RelVarReferencesMissing (S.Set RelVarName) |
141142-- errors returned from the distributed-process call handlers
142143data ServerError = RequestTimeoutError |
143144 ProcessDiedError String
144− deriving (Generic, Binary, Eq)
145+ deriving (Generic, Binary, Eq)
src/lib/ProjectM36/Relation/Show/Term.hs−10
@@ -38,16 +38,6 @@ boxBB = "┴"
3838boxC :: StringType
3939boxC = "┼"
4040
41−dboxH :: StringType
42−dboxH = "═"
43−dboxL :: StringType
44−dboxL = "╞"
45−dboxR :: StringType
46−dboxR = "╡"
47−
48−class TermSize a where
49− termLength :: a -> Int
50−
5141--represent a relation as a table similar to those drawn by Date
5242type Cell = StringType
5343type Table = ([Cell], [[Cell]]) --header, body
src/lib/ProjectM36/Server.hs+1
@@ -26,6 +26,7 @@ serverDefinition testBool ti = defaultProcess {
2626 apiHandlers = [
2727 handleCall (\conn (ExecuteHeadName sessionId) -> handleExecuteHeadName ti sessionId conn),
2828 handleCall (\conn (ExecuteRelationalExpr sessionId expr) -> handleExecuteRelationalExpr ti sessionId conn expr),
29+ handleCall (\conn (ExecuteDataFrameExpr sessionId expr) -> handleExecuteDataFrameExpr ti sessionId conn expr),
2930 handleCall (\conn (ExecuteDatabaseContextExpr sessionId expr) -> handleExecuteDatabaseContextExpr ti sessionId conn expr),
3031 handleCall (\conn (ExecuteDatabaseContextIOExpr sessionId expr) -> handleExecuteDatabaseContextIOExpr ti sessionId conn expr),
3132 handleCall (\conn (ExecuteGraphExpr sessionId expr) -> handleExecuteGraphExpr ti sessionId conn expr),
src/lib/ProjectM36/Server/EntryPoints.hs+7−1
@@ -3,6 +3,7 @@ import ProjectM36.Base hiding (inclusionDependencies)
33import ProjectM36.IsomorphicSchema
44import ProjectM36.Client as C
55import ProjectM36.Error
6+import ProjectM36.DataFrame
67import Control.Distributed.Process (Process, ProcessId)
78import Control.Distributed.Process.ManagedProcess (ProcessReply)
89import Control.Distributed.Process.ManagedProcess.Server (reply)
@@ -34,6 +35,11 @@ handleExecuteRelationalExpr :: Timeout -> SessionId -> Connection -> RelationalE
3435handleExecuteRelationalExpr ti sessionId conn expr = do
3536 ret <- timeoutOrDie ti (executeRelationalExpr sessionId conn expr)
3637 reply ret conn
38+
39+handleExecuteDataFrameExpr :: Timeout -> SessionId -> Connection -> DataFrameExpr -> Reply (Either RelationalError DataFrame)
40+handleExecuteDataFrameExpr ti sessionId conn expr = do
41+ ret <- timeoutOrDie ti (executeDataFrameExpr sessionId conn expr)
42+ reply ret conn
3743
3844handleExecuteDatabaseContextExpr :: Timeout -> SessionId -> Connection -> DatabaseContextExpr -> Reply (Either RelationalError ())
3945handleExecuteDatabaseContextExpr ti sessionId conn dbexpr = do
@@ -164,4 +170,4 @@ handleRetrieveTypeConstructorMapping :: Timeout -> SessionId -> Connection -> Re
164170handleRetrieveTypeConstructorMapping ti sessionId conn = do
165171 ret <- timeoutOrDie ti (C.typeConstructorMapping sessionId conn)
166172 reply ret conn
167−
173+
src/lib/ProjectM36/Server/RemoteCallTypes.hs+4−1
@@ -3,6 +3,7 @@ module ProjectM36.Server.RemoteCallTypes where
33import ProjectM36.Base
44import ProjectM36.IsomorphicSchema
55import ProjectM36.TransactionGraph
6+import ProjectM36.DataFrame
67import ProjectM36.TransGraphRelationalExpression
78import ProjectM36.Session
89import GHC.Generics
@@ -18,6 +19,8 @@ data Logout = Logout
1819 deriving (Binary, Generic)
1920data ExecuteRelationalExpr = ExecuteRelationalExpr SessionId RelationalExpr
2021 deriving (Binary, Generic)
22+data ExecuteDataFrameExpr = ExecuteDataFrameExpr SessionId DataFrameExpr
23+ deriving (Binary, Generic)
2124data ExecuteDatabaseContextExpr = ExecuteDatabaseContextExpr SessionId DatabaseContextExpr
2225 deriving (Binary, Generic)
2326data ExecuteDatabaseContextIOExpr = ExecuteDatabaseContextIOExpr SessionId DatabaseContextIOExpr
@@ -65,4 +68,4 @@ data RetrieveSessionIsDirty = RetrieveSessionIsDirty SessionId
6568data ExecuteAutoMergeToHead = ExecuteAutoMergeToHead SessionId MergeStrategy HeadName
6669 deriving (Binary, Generic)
6770data RetrieveTypeConstructorMapping = RetrieveTypeConstructorMapping SessionId
68− deriving (Binary, Generic)
71+ deriving (Binary, Generic)
src/lib/ProjectM36/Tuple.hs+2−2
@@ -188,7 +188,7 @@ verifyTuple :: Attributes -> RelationTuple -> Either RelationalError RelationTup
188188verifyTuple attrs tuple = let attrsTypes = V.map atomType attrs
189189 tupleTypes = V.map atomTypeForAtom (tupleAtoms tuple) in
190190 if V.length attrs /= V.length tupleTypes then
191− Left $ TupleAttributeCountMismatchError 0
191+ Left $ traceShow (attrs, tupleTypes) $ TupleAttributeCountMismatchError 0
192192 else do
193193 mapM_ (uncurry atomTypeVerify) (V.zip attrsTypes tupleTypes)
194194 Right tuple
@@ -207,4 +207,4 @@ reorderTuple attrs tupIn = if tupleAttributes tupIn == attrs then
207207
208208--used in Generics derivation for ADTs without named attributes
209209trimTuple :: Int -> RelationTuple -> RelationTuple
210−trimTuple index (RelationTuple attrs vals) = RelationTuple (V.drop index attrs) (V.drop index vals)
210+trimTuple index (RelationTuple attrs vals) = RelationTuple (V.drop index attrs) (V.drop index vals)
test/DataFrame.hsnew file+34
@@ -0,0 +1,34 @@
1+import ProjectM36.Client
2+import ProjectM36.DataFrame (atomForAttributeName, tuples)
3+import TutorialD.Interpreter.TestBase
4+
5+import Test.HUnit
6+import System.Exit
7+import qualified Data.Set as S
8+
9+testList :: Test
10+testList = TestList []
11+
12+main :: IO ()
13+main = do
14+ tcounts <- runTestTT testList
15+ if errors tcounts + failures tcounts > 0 then exitFailure else exitSuccess
16+
17+testOrderBy :: Test
18+testOrderBy = TestCase $ do
19+ (sessionId, dbconn) <- dateExamplesConnection emptyNotificationCallback
20+ Right df <- executeDataFrameExpr sessionId dbconn (
21+ DataFrameExpr {
22+ convertExpr = Project (AttributeNames (S.singleton "status")) (RelationVariable "s" ()),
23+ orderExprs = [AttributeOrderExpr "status" AscendingOrder],
24+ offset = Nothing,
25+ limit = Nothing
26+ })
27+ let vals = map (\tup -> case atomForAttributeName "status" tup of
28+ Left err -> error (show err)
29+ Right atom -> atom) (tuples df)
30+ assertEqual "sort order of s" [IntegerAtom 10, IntegerAtom 20, IntegerAtom 30] vals
31+
32+--testOffset :: Test
33+
34+--testLimit :: Test
test/Relation/Basic.hs+1−1
@@ -109,4 +109,4 @@ testDuplicateAttributes = TestCase $ do
109109testExistingRelationType :: Test
110110testExistingRelationType = TestCase $ do
111111 let typeResult = runReader (typeForRelationalExpr (ExistingRelation relationTrue)) (RelationalExprStateElems DBC.empty)
112− assertEqual "ExistingRelation with tuples type" (Right relationFalse) typeResult
112+ assertEqual "ExistingRelation with tuples type" (Right relationFalse) typeResult
test/TutorialD/Interpreter.hs+1−1
@@ -640,4 +640,4 @@ testAtomFunctionArgumentMismatch = TestCase $ do
640640 expectTutorialDErr sessionId dbconn (T.isPrefixOf err1) "x:=relation{tuple{a 5}} where ^gt(@a,1.5)"
641641 --wrong argument count
642642 let err2 = "FunctionArgumentCountMismatchError"
643− expectTutorialDErr sessionId dbconn (T.isPrefixOf err2) "x:=relation{tuple{a 5}} where ^gt(@a,1,3)"
643+ expectTutorialDErr sessionId dbconn (T.isPrefixOf err2) "x:=relation{tuple{a 5}} where ^gt(@a,1,3)"