on master help sign in
add example of using RelationAtom (nested relations) with Tupleable
700f406AgentM
examples/CustomTupleable.hsnew file+67
@@ -0,0 +1,67 @@
1+{-# LANGUAGE DeriveGeneric, DeriveAnyClass, OverloadedStrings #-}
2+--this example shows how to implement a non-generics-defined Tupleable instance which is required in scenarios where Haskell-side types are not supported server-side or where one wishes to represent a nested relation
3+import ProjectM36.Client
4+import ProjectM36.Tuple
5+import ProjectM36.Tupleable
6+import ProjectM36.Relation
7+import ProjectM36.Atom
8+import ProjectM36.Attribute as A
9+import qualified Data.Set as S
10+import qualified Data.Map as M
11+import Data.Text (Text)
12+import GHC.Generics
13+import Data.Proxy
14+
15+--in this contrived example, we wish to represent one relation with a nested relation of comments
16+data Blog = Blog {
17+ title :: Text,
18+ comments :: S.Set Comment
19+ } deriving (Show)
20+
21+data Comment = Comment {
22+ authorName :: Text,
23+ comment :: Text
24+ } deriving (Eq, Show, Generic, Ord)
25+
26+instance Tupleable Comment
27+
28+instance Tupleable Blog where
29+ toTuple blogentry =
30+ mkRelationTupleFromMap (M.fromList [("title", TextAtom (title blogentry)),
31+ ("comments", RelationAtom relFromComments)])
32+ where
33+ commentTuples = map toTuple (S.toList (comments blogentry))
34+ relFromComments = case mkRelationFromTuples (toAttributes (Proxy :: Proxy Comment)) commentTuples of
35+ Left err -> error (show err)
36+ Right rel -> rel
37+
38+ fromTuple tupIn = do
39+ titleAtom <- atomForAttributeName "title" tupIn
40+ commentsAtom <- atomForAttributeName "comments" tupIn
41+ commentsRel <- relationForAtom commentsAtom
42+ comments' <- mapM fromTuple (tuplesList commentsRel)
43+ pure Blog {
44+ title = atomToText titleAtom,
45+ comments = S.fromList comments'}
46+
47+ toAttributes _ = A.attributesFromList [Attribute "title" TextAtomType,
48+ Attribute "comments" $ RelationAtomType (toAttributes (Proxy :: Proxy Comment))]
49+
50+main :: IO ()
51+main = do
52+ let exampleBlog = Blog { title = "Cat Pics",
53+ comments = S.fromList [Comment {authorName = "Steve",
54+ comment = "great"},
55+ Comment {authorName = "Bob",
56+ comment = "enough"}
57+ ]}
58+ print (toTuple exampleBlog)
59+ print (fromTuple (toTuple exampleBlog) :: Either RelationalError Blog)
60+
61+
62+
63+
64+
65+
66+
67+
project-m36.cabal+9
@@ -44,6 +44,8 @@ Library
44 ,vector
44 ,vector
45 ,parallel
45 ,parallel
46 ,monad-parallel
46 ,monad-parallel
47+ ,streamly
48+ ,exceptions
47 ,transformers
49 ,transformers
48 ,gnuplot
50 ,gnuplot
49 ,binary
51 ,binary
@@ -427,6 +429,13 @@ Executable Example-Hair
427 Main-Is: examples/hair.hs
429 Main-Is: examples/hair.hs
428 GHC-Options: -Wall
430 GHC-Options: -Wall
429
431
432+Executable Example-CustomTupleable
433+ Default-Language: Haskell2010
434+ Default-Extensions: OverloadedStrings
435+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, uuid, stm, deepseq, deepseq-generics, binary, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, megaparsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers, list-t, aeson, path-pieces, either, conduit, http-api-data, template-haskell, ghc, ghc-paths, project-m36
436+ Main-Is: examples/CustomTupleable.hs
437+ GHC-Options: -Wall
438+
430Test-Suite test-scripts
439Test-Suite test-scripts
431 Default-Language: Haskell2010
440 Default-Language: Haskell2010
432 Default-Extensions: OverloadedStrings
441 Default-Extensions: OverloadedStrings
src/lib/ProjectM36/Relation.hs+4−1
@@ -324,4 +324,7 @@ randomizeTupleOrder (Relation attrs tupSet) = do
324-- returns a tuple from the tupleset- this is useful for priming folds over the tuples
324-- returns a tuple from the tupleset- this is useful for priming folds over the tuples
325oneTuple :: Relation -> Maybe RelationTuple
325oneTuple :: Relation -> Maybe RelationTuple
326oneTuple (Relation _ (RelationTupleSet [])) = Nothing
326oneTuple (Relation _ (RelationTupleSet [])) = Nothing
327−oneTuple (Relation _ (RelationTupleSet (x:_))) = Just x
327+oneTuple (Relation _ (RelationTupleSet (x:_))) = Just x
328+
329+tuplesList :: Relation -> [RelationTuple]
330+tuplesList (Relation _ tupleSet) = asList tupleSet