on master help sign in
implement session support in persistent driver and tutd
commitac0c8adeb8c5e786acdcecfb5c8f5a67b701d0b4 authorAgentM <agentm@themactionfaction.com> dateMon 30 Nov 2015, 22:11 (11 years ago) parentf128074
8 files changed+164−129
Database/Persist/ProjectM36.hs+71−66 ProjectM36/Client.hs+6 ProjectM36/Server/EntryPoints.hs+2−1 TutorialD/Interpreter.hs+17−17 TutorialD/Interpreter/RODatabaseContextOperator.hs+22−20 TutorialD/Interpreter/TransactionGraphOperator.hs+2−2 TutorialD/tutd.hs+25−8 project-m36.cabal+19−15
Database/Persist/ProjectM36.hs+71−66
@@ -34,10 +34,10 @@ import Data.Time.Calendar (Day)
3434import Data.ByteString (ByteString)
3535import Web.HttpApiData (ToHttpApiData(..), FromHttpApiData(..), parseUrlPieceWithPrefix, readTextData)
3636
37−type ProjectM36Backend = C.Connection
37+type ProjectM36Backend = (C.SessionId, C.Connection)
3838
3939--convert a PersistEntity to a RelationTuple
40−recordAsTuple :: forall record. (PersistEntity record, PersistEntityBackend record ~ C.Connection)
40+recordAsTuple :: forall record. (PersistEntity record, PersistEntityBackend record ~ ProjectM36Backend)
4141 => Maybe U.UUID -> record -> Either RelationalError RelationTuple
4242recordAsTuple uuid record = do -- if the uuid is passed in, set the idDBName attribute
4343 let entInfo = zip entFields entValues
@@ -47,7 +47,7 @@ recordAsTuple uuid record = do -- if the uuid is passed in, set the idDBName att
4747 atomVec <- recordAsAtoms uuid attrVec record
4848 return $ RelationTuple attrVec atomVec
4949
50−recordAttributes :: forall record. (PersistEntity record, PersistEntityBackend record ~ C.Connection)
50+recordAttributes :: forall record. (PersistEntity record, PersistEntityBackend record ~ ProjectM36Backend)
5151 => [(EmbedFieldDef, PersistValue)] -> record -> Either RelationalError Attributes
5252recordAttributes entInfo record = do
5353 let convertAttr = uncurry fieldDefAsAttribute
@@ -89,7 +89,7 @@ atomAsPersistValue atom@(Atom atomv) = if typeRep (Proxy :: Proxy Int) == typeOf
8989 else
9090 error "missing conversion"
9191
92−recordAsAtoms :: forall record. (PersistEntity record, PersistEntityBackend record ~ C.Connection)
92+recordAsAtoms :: forall record. (PersistEntity record, PersistEntityBackend record ~ ProjectM36Backend)
9393 => Maybe U.UUID -> Attributes -> record -> Either RelationalError (V.Vector Atom)
9494recordAsAtoms freshUUID _ record = do
9595 let pValues = map toPersistValue $ toPersistFields record
@@ -102,7 +102,7 @@ recordAsAtoms freshUUID _ record = do
102102 Just uuid -> [Atom $ T.pack (U.toString uuid)] ++ atoms
103103
104104--used by insert operations
105−recordsAsRelation :: forall record. (PersistEntity record, PersistEntityBackend record ~ C.Connection) =>
105+recordsAsRelation :: forall record. (PersistEntity record, PersistEntityBackend record ~ ProjectM36Backend) =>
106106 [(Maybe U.UUID, record)] -> Either RelationalError Relation
107107recordsAsRelation [] = Left EmptyTuplesError
108108recordsAsRelation recordZips = do
@@ -112,7 +112,7 @@ recordsAsRelation recordZips = do
112112
113113keyFromValuesOrDie :: (Trans.MonadIO m,
114114 PersistEntity record,
115− PersistEntityBackend record ~ C.Connection
115+ PersistEntityBackend record ~ ProjectM36Backend
116116 ) => [PersistValue] -> m (Key record)
117117keyFromValuesOrDie val = case keyFromValues val of
118118 Right k -> return k
@@ -120,16 +120,16 @@ keyFromValuesOrDie val = case keyFromValues val of
120120
121121insertNewRecords :: (Trans.MonadIO m,
122122 PersistEntity record,
123− PersistEntityBackend record ~ C.Connection) =>
124− [U.UUID] -> [record] -> ReaderT C.Connection m [Key record]
123+ PersistEntityBackend record ~ ProjectM36Backend) =>
124+ [U.UUID] -> [record] -> ReaderT ProjectM36Backend m [Key record]
125125insertNewRecords uuids records = do
126126 let recordsZip = zip (map Just uuids) records
127127 insertExpr = Insert (relVarNameFromRecord $ head records)
128128 case recordsAsRelation recordsZip of
129129 Left err -> throw $ PersistError (T.pack $ show err)
130130 Right rel -> do
131− conn <- ask
132− Trans.liftIO $ executeDatabaseContextExpr conn (insertExpr (ExistingRelation rel))
131+ (sessionId, conn) <- ask
132+ Trans.liftIO $ executeDatabaseContextExpr sessionId conn (insertExpr (ExistingRelation rel))
133133 mapM (\uuid -> keyFromValuesOrDie [PersistText $ T.pack (U.toString uuid)]) uuids
134134
135135throwIOPersistError :: (Trans.MonadIO m) => String -> m a
@@ -138,13 +138,13 @@ throwIOPersistError msg = Trans.liftIO $ throwIO $ PersistError (T.pack msg)
138138lookupByKey :: forall record m.
139139 (Trans.MonadIO m,
140140 PersistEntity record,
141− PersistEntityBackend record ~ C.Connection)
142− => Key record -> ReaderT C.Connection m (Maybe (Entity record))
141+ PersistEntityBackend record ~ ProjectM36Backend)
142+ => Key record -> ReaderT ProjectM36Backend m (Maybe (Entity record))
143143lookupByKey key = do
144144 (relVarName, restrictionPredicate) <- commonKeyQueryProperties key
145145 let query = Restrict restrictionPredicate (RelationVariable relVarName)
146− conn <- ask
147− resultRel <- Trans.liftIO $ C.executeRelationalExpr conn query
146+ (sessionId, conn) <- ask
147+ resultRel <- Trans.liftIO $ C.executeRelationalExpr sessionId conn query
148148 case resultRel of
149149 Left err -> throwIOPersistError ("executeRelationExpr error: " ++ show err)
150150 Right resultRel' -> case singletonTuple resultRel' of
@@ -156,7 +156,7 @@ lookupByKey key = do
156156
157157fromPersistValuesThrow :: (Trans.MonadIO m,
158158 PersistEntity record,
159− PersistEntityBackend record ~ C.Connection) => EntityDef -> RelationTuple -> m (Entity record)
159+ PersistEntityBackend record ~ ProjectM36Backend) => EntityDef -> RelationTuple -> m (Entity record)
160160fromPersistValuesThrow entDef tuple = do
161161 let body = fromPersistValues $ map getValue (entityFields entDef)
162162 getValue field = case atomForAttributeName (unDBName (fieldDB field)) tuple of
@@ -171,7 +171,7 @@ fromPersistValuesThrow entDef tuple = do
171171 Left err -> throwIOPersistError (show err)
172172 Right body' -> return $ Entity key body'
173173
174−commonKeyQueryProperties :: (Trans.MonadIO m, PersistEntityBackend val ~ C.Connection, PersistEntity val) => Key val -> ReaderT C.Connection m (RelVarName, RestrictionPredicateExpr)
174+commonKeyQueryProperties :: (Trans.MonadIO m, PersistEntityBackend val ~ ProjectM36Backend, PersistEntity val) => Key val -> ReaderT ProjectM36Backend m (RelVarName, RestrictionPredicateExpr)
175175commonKeyQueryProperties key = do
176176 let matchUUID = keyToUUID key
177177 keyAttributeName = unDBName (fieldDB $ entityId entityInfo)
@@ -181,19 +181,19 @@ commonKeyQueryProperties key = do
181181 restrictionPredicate = AttributeEqualityPredicate keyAttributeName (NakedAtomExpr (Atom matchUUIDText))
182182 return (relVarName, restrictionPredicate)
183183
184−deleteByKey :: (Trans.MonadIO m, PersistEntityBackend val ~ C.Connection, PersistEntity val) => Key val -> ReaderT C.Connection m (Bool)
184+deleteByKey :: (Trans.MonadIO m, PersistEntityBackend val ~ ProjectM36Backend, PersistEntity val) => Key val -> ReaderT ProjectM36Backend m (Bool)
185185deleteByKey key = do
186186 (relVarName, restrictionPredicate) <- commonKeyQueryProperties key
187187 let query = Delete relVarName restrictionPredicate
188− conn <- ask
189− maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr conn query
188+ (sessionId, conn) <- ask
189+ maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr sessionId conn query
190190 return $ isJust maybeErr
191191
192192--convert persistent update list to ProjectM36 Update map
193193updatesToUpdateMap :: (Trans.MonadIO m,
194− PersistEntityBackend val ~ C.Connection,
194+ PersistEntityBackend val ~ ProjectM36Backend,
195195 PersistEntity val) =>
196− [DP.Update val] -> ReaderT C.Connection m (M.Map AttributeName Atom)
196+ [DP.Update val] -> ReaderT ProjectM36Backend m (M.Map AttributeName Atom)
197197updatesToUpdateMap updates = do
198198 let convertMap upd = case updateUpdate upd of
199199 DP.Assign -> let attrName = unDBName $ fieldDB $ updateFieldDef upd
@@ -205,24 +205,24 @@ updatesToUpdateMap updates = do
205205 updateAtomList <- mapM convertMap updates
206206 return $ M.fromList updateAtomList
207207
208−updateByKey :: (Trans.MonadIO m, PersistEntityBackend val ~ C.Connection, PersistEntity val) => Key val -> [DP.Update val] -> ReaderT C.Connection m ()
208+updateByKey :: (Trans.MonadIO m, PersistEntityBackend val ~ ProjectM36Backend, PersistEntity val) => Key val -> [DP.Update val] -> ReaderT ProjectM36Backend m ()
209209updateByKey key updates = do
210210 (relVarName, restrictionPredicate) <- commonKeyQueryProperties key
211211 updateMap <- updatesToUpdateMap updates
212212 let query = Update relVarName updateMap restrictionPredicate
213− conn <- ask
214− maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr conn query
213+ (sessionId, conn) <- ask
214+ maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr sessionId conn query
215215 case maybeErr of
216216 Just err -> throwIOPersistError ("executeDatabaseExpr error" ++ show err)
217217 Nothing -> return ()
218218
219219--set the truth unconditionally
220−repsertByKey :: (Trans.MonadIO m, C.Connection ~ PersistEntityBackend val, PersistEntity val) => Key val -> val -> ReaderT C.Connection m ()
220+repsertByKey :: (Trans.MonadIO m, ProjectM36Backend ~ PersistEntityBackend val, PersistEntity val) => Key val -> val -> ReaderT ProjectM36Backend m ()
221221repsertByKey key val = do
222222 _ <- delete key
223223 insertKey key val
224224
225−replaceByKey :: (Trans.MonadIO m, C.Connection ~ PersistEntityBackend val, PersistEntity val) => Key val -> val -> ReaderT C.Connection m ()
225+replaceByKey :: (Trans.MonadIO m, ProjectM36Backend ~ PersistEntityBackend val, PersistEntity val) => Key val -> val -> ReaderT ProjectM36Backend m ()
226226replaceByKey key val = do
227227 deletionSuccess <- deleteByKey key
228228 when (not deletionSuccess) (Trans.liftIO $ throwIO $ PersistError "entity missing during replace")
@@ -256,10 +256,10 @@ keyToUUID key = case keyToValues key of
256256 Just uuid -> uuid
257257 _ -> error "unexpected persist value in key construction"
258258
259−instance ToHttpApiData (BackendKey C.Connection) where
259+instance ToHttpApiData (BackendKey ProjectM36Backend) where
260260 toUrlPiece = T.pack . U.toString . unPM36Key
261261
262−instance FromHttpApiData (BackendKey C.Connection) where
262+instance FromHttpApiData (BackendKey ProjectM36Backend) where
263263 parseUrlPiece input = do
264264 s <- parseUrlPieceWithPrefix "o" input <!> return input
265265 ProjectM36Key <$> readTextData s
@@ -268,8 +268,8 @@ instance FromHttpApiData (BackendKey C.Connection) where
268268 Left _ <!> y = y
269269 x <!> _ = x
270270
271−instance PersistStore C.Connection where
272− newtype BackendKey C.Connection = ProjectM36Key { unPM36Key :: U.UUID }
271+instance PersistStore ProjectM36Backend where
272+ newtype BackendKey ProjectM36Backend = ProjectM36Key { unPM36Key :: U.UUID }
273273 deriving (Show, Read, Eq, Ord, PersistField)
274274
275275 insertMany [] = return []
@@ -305,21 +305,21 @@ instance PersistStore C.Connection where
305305 --update :: (MonadIO m, PersistEntity val, backend ~ PersistEntityBackend val) => Key val -> [Update val] -> ReaderT backend m ()
306306 update = updateByKey
307307
308−instance FromJSON (BackendKey C.Connection) where
308+instance FromJSON (BackendKey ProjectM36Backend) where
309309 parseJSON = withText "ProjectM36Key" $ \t -> maybe (fail "Invalid UUID") (return . ProjectM36Key) (U.fromString (T.unpack t))
310310
311−instance ToJSON (BackendKey C.Connection) where
311+instance ToJSON (BackendKey ProjectM36Backend) where
312312 toJSON (ProjectM36Key uuid) = toJSON $ U.toString uuid
313313
314314--wrapped version which throws exceptions
315−executeDatabaseContextExpr :: C.Connection -> DatabaseExpr -> IO ()
316−executeDatabaseContextExpr conn expr = do
317− res <- C.executeDatabaseContextExpr conn expr
315+executeDatabaseContextExpr :: C.SessionId -> C.Connection -> DatabaseExpr -> IO ()
316+executeDatabaseContextExpr sessionId conn expr = do
317+ res <- C.executeDatabaseContextExpr sessionId conn expr
318318 case res of
319319 Nothing -> return ()
320320 Just err -> throwIO (PersistError $ T.pack (show err))
321321
322−relVarNameFromRecord :: (PersistEntity record, PersistEntityBackend record ~ C.Connection)
322+relVarNameFromRecord :: (PersistEntity record, PersistEntityBackend record ~ ProjectM36Backend)
323323 => record -> RelVarName
324324relVarNameFromRecord = unDBName . entityDB . entityDef . Just
325325
@@ -346,8 +346,9 @@ instance FromJSON C.ConnectionInfo where
346346 return ctype
347347
348348instance PersistConfig C.ConnectionInfo where
349− type PersistConfigBackend C.ConnectionInfo = ReaderT C.Connection
350− type PersistConfigPool C.ConnectionInfo = C.Connection
349+ -- | Hold onto a connection as well a default session.
350+ type PersistConfigBackend C.ConnectionInfo = ReaderT ProjectM36Backend
351+ type PersistConfigPool C.ConnectionInfo = ProjectM36Backend
351352
352353 loadConfig = parseJSON
353354 applyEnv = return -- no environment variables are used
@@ -355,17 +356,21 @@ instance PersistConfig C.ConnectionInfo where
355356 connErr <- C.connectProjectM36 conf
356357 case connErr of
357358 Left err -> throwIO $ PersistError ("Failed to create connection: " `T.append` (T.pack $ show err))
358− Right conn -> return conn
359+ Right conn -> do
360+ eSession <- C.createSessionAtHead "master" conn
361+ case eSession of
362+ Left err -> throwIO $ PersistError ("Failed to create session: " `T.append` (T.pack $ show err))
363+ Right sessionId -> pure (sessionId, conn)
359364 --runPool :: (MonadBaseControl IO m, MonadIO m) => c -> PersistConfigBackend c m a -> PersistConfigPool c -> m a
360365 runPool _ r = runReaderT r
361366
362−withProjectM36Conn :: (Monad m, Trans.MonadIO m) => C.ConnectionInfo -> (C.Connection -> m a) -> m a
367+withProjectM36Conn :: (Monad m, Trans.MonadIO m) => C.ConnectionInfo -> (ProjectM36Backend -> m a) -> m a
363368withProjectM36Conn conf connReader = do
364− conn <- Trans.liftIO $ createPoolConfig conf
365− connReader conn
369+ backend <- Trans.liftIO $ createPoolConfig conf
370+ connReader backend
366371
367−runProjectM36Conn :: (Trans.MonadIO m) => ReaderT C.Connection m a -> C.Connection -> m a
368−runProjectM36Conn m1 conn = runReaderT m1 conn
372+runProjectM36Conn :: (Trans.MonadIO m) => ReaderT ProjectM36Backend m a -> (C.SessionId, C.Connection) -> m a
373+runProjectM36Conn m1 (sessionId, conn) = runReaderT m1 (sessionId, conn)
369374
370375instance PathPiece (BackendKey ProjectM36Backend) where
371376 toPathPiece (ProjectM36Key uuid) = U.toText uuid
@@ -376,7 +381,7 @@ instance PathPiece (BackendKey ProjectM36Backend) where
376381instance Sql.PersistFieldSql U.UUID where
377382 sqlType _ = Sql.SqlOther "doesn't make much sense for ProjectM36"
378383
379−instance Sql.PersistFieldSql (BackendKey C.Connection) where
384+instance Sql.PersistFieldSql (BackendKey ProjectM36Backend) where
380385 sqlType _ = Sql.SqlOther "doesn't make much sense for ProjectM36"
381386
382387persistUniqueToRestrictionPredicate :: PersistEntity record => Unique record -> Either RelationalError RestrictionPredicateExpr
@@ -387,9 +392,9 @@ persistUniqueToRestrictionPredicate unique = do
387392 andify ((attrName, atom):xs) = AndPredicate (AttributeEqualityPredicate attrName (NakedAtomExpr atom)) $ andify xs
388393 return $ andify (zip attrNames atoms)
389394
390−instance PersistUnique C.Connection where
395+instance PersistUnique ProjectM36Backend where
391396 getBy unique = do
392− conn <- ask
397+ (sessionId, conn) <- ask
393398 let predicate = persistUniqueToRestrictionPredicate unique
394399 relVarName = unDBName $ entityDB entDef
395400 entDef = entityDef $ dummyFromUnique unique
@@ -398,7 +403,7 @@ instance PersistUnique C.Connection where
398403 Left err -> throwRelErr err
399404 Right predicate' -> do
400405 let restrictExpr = Restrict predicate' (RelationVariable relVarName)
401− singletonRel <- Trans.liftIO $ C.executeRelationalExpr conn restrictExpr
406+ singletonRel <- Trans.liftIO $ C.executeRelationalExpr sessionId conn restrictExpr
402407 case singletonRel of
403408 Left err -> throwRelErr err
404409 Right singletonRel' -> do
@@ -413,7 +418,7 @@ instance PersistUnique C.Connection where
413418 newEnt <- Trans.liftIO $ fromPersistValuesThrow entDef tuple
414419 return $ Just newEnt
415420 deleteBy unique = do
416− conn <- ask
421+ (sessionId, conn) <- ask
417422 let predicate = persistUniqueToRestrictionPredicate unique
418423 relVarName = unDBName $ entityDB entDef
419424 entDef = entityDef $ dummyFromUnique unique
@@ -422,12 +427,12 @@ instance PersistUnique C.Connection where
422427 Left err -> throwRelErr err
423428 Right predicate' -> do
424429 let deleteExpr = Delete relVarName predicate'
425− maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr conn deleteExpr
430+ maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr sessionId conn deleteExpr
426431 case maybeErr of
427432 Just err -> throwRelErr err
428433 Nothing -> return ()
429434
430−multiFilterAsRestrictionPredicate :: (PersistEntity val, PersistEntityBackend val ~ C.Connection) => Bool -> [Filter val] -> Either RelationalError RestrictionPredicateExpr
435+multiFilterAsRestrictionPredicate :: (PersistEntity val, PersistEntityBackend val ~ ProjectM36Backend) => Bool -> [Filter val] -> Either RelationalError RestrictionPredicateExpr
431436multiFilterAsRestrictionPredicate _ [] = Right $ TruePredicate
432437multiFilterAsRestrictionPredicate andOr (x:xs) = do
433438 let predicate = if andOr then AndPredicate else OrPredicate
@@ -438,7 +443,7 @@ multiFilterAsRestrictionPredicate andOr (x:xs) = do
438443filterValueToPersistValues :: forall a. PersistField a => Either a [a] -> [PersistValue]
439444filterValueToPersistValues v = map toPersistValue $ either return id v
440445
441−filterAsRestrictionPredicate :: (PersistEntity val, PersistEntityBackend val ~ C.Connection) => Filter val -> Either RelationalError RestrictionPredicateExpr
446+filterAsRestrictionPredicate :: (PersistEntity val, PersistEntityBackend val ~ ProjectM36Backend) => Filter val -> Either RelationalError RestrictionPredicateExpr
442447filterAsRestrictionPredicate filterIn = case filterIn of
443448 FilterAnd filters -> multiFilterAsRestrictionPredicate True filters
444449 FilterOr filters -> multiFilterAsRestrictionPredicate False filters
@@ -456,7 +461,7 @@ filterAsRestrictionPredicate filterIn = case filterIn of
456461 op -> Left $ AtomOperatorNotSupported $ T.pack (show op)
457462 Right _ -> Left $ AtomTypeNotSupported attrName
458463
459−updateToUpdateTuple :: (PersistEntity val, PersistEntityBackend val ~ C.Connection) => DPT.Update val -> Either RelationalError (AttributeName, Atom)
464+updateToUpdateTuple :: (PersistEntity val, PersistEntityBackend val ~ ProjectM36Backend) => DPT.Update val -> Either RelationalError (AttributeName, Atom)
460465updateToUpdateTuple (BackendUpdate _) = error "BackendUpdate not supported"
461466updateToUpdateTuple (DPT.Update field value op) = let attrName = unDBName $ fieldDB (persistFieldDef field)
462467 atom = persistValueAtom $ toPersistValue value
@@ -466,7 +471,7 @@ updateToUpdateTuple (DPT.Update field value op) = let attrName = unDBName $ fiel
466471 Just atom' -> Right $ (attrName, atom')
467472 op' -> Left $ AtomOperatorNotSupported $ T.pack (show op')
468473
469−selectionFromRestriction :: (PersistEntity val, PersistEntityBackend val ~ backend, Trans.MonadIO m, backend ~ C.Connection) => [Filter val] -> ReaderT backend m (Either RelationalError RelationalExpr)
474+selectionFromRestriction :: (PersistEntity val, PersistEntityBackend val ~ backend, Trans.MonadIO m, backend ~ ProjectM36Backend) => [Filter val] -> ReaderT backend m (Either RelationalError RelationalExpr)
470475selectionFromRestriction filters = do
471476 runEitherT $ do
472477 restrictionPredicate <- hoistEither $ multiFilterAsRestrictionPredicate True filters
@@ -475,10 +480,10 @@ selectionFromRestriction filters = do
475480 right $ Restrict restrictionPredicate (RelationVariable relVarName)
476481
477482
478−instance PersistQuery C.Connection where
483+instance PersistQuery ProjectM36Backend where
479484 updateWhere _ [] = return ()
480485 updateWhere filters updates = do
481− conn <- ask
486+ (sessionId, conn) <- ask
482487 e <- runEitherT $ do
483488 restrictionPredicate <- hoistEither $ multiFilterAsRestrictionPredicate True filters
484489 tuples <- hoistEither $ mapM updateToUpdateTuple updates
@@ -486,7 +491,7 @@ instance PersistQuery C.Connection where
486491 entDef = entityDef $ dummyFromUpdate (head updates)
487492 relVarName = unDBName $ entityDB entDef
488493 updateExpr = Update relVarName updateMap restrictionPredicate
489− maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr conn updateExpr
494+ maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr sessionId conn updateExpr
490495 case maybeErr of
491496 Just err -> left err
492497 Nothing -> right ()
@@ -495,13 +500,13 @@ instance PersistQuery C.Connection where
495500 Right () -> return ()
496501
497502 deleteWhere filters = do
498− conn <- ask
503+ (sessionId, conn) <- ask
499504 e <- runEitherT $ do
500505 restrictionPredicate <- hoistEither $ multiFilterAsRestrictionPredicate True filters
501506 let entDef = entityDef $ dummyFromFilters filters
502507 relVarName = unDBName $ entityDB entDef
503508 deleteExpr = Delete relVarName restrictionPredicate
504− maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr conn deleteExpr
509+ maybeErr <- Trans.liftIO $ C.executeDatabaseContextExpr sessionId conn deleteExpr
505510 case maybeErr of
506511 Just err -> left err
507512 Nothing -> right ()
@@ -510,7 +515,7 @@ instance PersistQuery C.Connection where
510515 Right () -> return ()
511516
512517 count filters = do
513− conn <- ask
518+ (sessionId, conn) <- ask
514519 e <- runEitherT $ do
515520 restrictionPredicate <- hoistEither $ multiFilterAsRestrictionPredicate True filters
516521 let entDef = entityDef $ dummyFromFilters filters
@@ -520,7 +525,7 @@ instance PersistQuery C.Connection where
520525 groupExpr = Group allAttrNames "persistcountrel" (Restrict restrictionPredicate (RelationVariable relVarName))
521526 tupleExpr = AttributeTupleExpr "persistcount" (FunctionAtomExpr "count" [AttributeAtomExpr "persistcountrel"])
522527 countExpr = Extend tupleExpr groupExpr
523− rel <- Trans.liftIO $ C.executeRelationalExpr conn countExpr
528+ rel <- Trans.liftIO $ C.executeRelationalExpr sessionId conn countExpr
524529 case rel of
525530 Left err -> left err
526531 Right rel' -> case singletonTuple rel' of
@@ -535,13 +540,13 @@ instance PersistQuery C.Connection where
535540 --no select options currently supported (sorting, limiting)
536541 selectSourceRes _ (_:_) = Trans.liftIO $ throwIO $ PersistError "select options not yet supported"
537542 selectSourceRes filters [] = do
538− conn <- ask
543+ (sessionId, conn) <- ask
539544 entities <- runEitherT $ do
540545 restrictionExpr <- (lift $ selectionFromRestriction filters) >>= hoistEither
541546 --restrictionExpr' <- hoistEither restrictionExpr
542547 let entDef = entityDef $ dummyFromFilters filters
543548 let tupleMapper tuple = Trans.liftIO $ fromPersistValuesThrow entDef tuple
544− rel <- Trans.liftIO $ C.executeRelationalExpr conn restrictionExpr
549+ rel <- Trans.liftIO $ C.executeRelationalExpr sessionId conn restrictionExpr
545550 case rel of
546551 Left err -> Trans.liftIO $ throwIO $ PersistError (T.pack (show err))
547552 Right (Relation _ tupleSet) -> mapM tupleMapper $ asList tupleSet --refactor to use some relation accessors- here we convert a relation to a matrix, effectively (especially to support future sorting)
@@ -551,13 +556,13 @@ instance PersistQuery C.Connection where
551556
552557 selectKeysRes _ (_:_) = Trans.liftIO $ throwIO $ PersistError "select options not yet supported"
553558 selectKeysRes filters [] = do
554− conn <- ask
559+ (sessionId, conn) <- ask
555560 keys <- runEitherT $ do
556561 restrictionExpr <- (lift $ selectionFromRestriction filters) >>= hoistEither
557562 let keyAttrNames = ["id"] --no support for multi-attribute keys yet
558563 keyExpr = Project (AttributeNames $ S.fromList keyAttrNames) restrictionExpr
559− (Relation _ tupleSet) <- (Trans.liftIO $ C.executeRelationalExpr conn keyExpr) >>= hoistEither
560− let keyMapper :: (PersistEntity record, Trans.MonadIO m) => RelationTuple -> EitherT RelationalError (ReaderT C.Connection m) (Key record)
564+ (Relation _ tupleSet) <- (Trans.liftIO $ C.executeRelationalExpr sessionId conn keyExpr) >>= hoistEither
565+ let keyMapper :: (PersistEntity record, Trans.MonadIO m) => RelationTuple -> EitherT RelationalError (ReaderT ProjectM36Backend m) (Key record)
561566 keyMapper tuple = do
562567 atoms <- hoistEither (atomsForAttributeNames (V.fromList keyAttrNames) tuple)
563568 case keyFromValues (map atomAsPersistValue (V.toList atoms)) of
ProjectM36/Client.hs+6
@@ -24,6 +24,7 @@ module ProjectM36.Client
2424 headTransactionUUID,
2525 defaultDatabaseName,
2626 defaultRemoteConnectionInfo,
27+ defaultHeadName,
2728 PersistenceStrategy(..),
2829 RelationalExpr(..),
2930 DatabaseExpr(..),
@@ -37,6 +38,8 @@ module ProjectM36.Client
3738 Atomable,
3839 NodeId(..),
3940 Atom(..),
41+ Session,
42+ SessionId,
4043 AtomType(..)) where
4144import ProjectM36.Base hiding (inclusionDependencies) --defined in this module as well
4245import qualified ProjectM36.Base as B
@@ -87,6 +90,9 @@ defaultServerPort = 6543
8790defaultDatabaseName :: DatabaseName
8891defaultDatabaseName = "base"
8992
93+defaultHeadName :: HeadName
94+defaultHeadName = "master"
95+
9096defaultRemoteConnectionInfo :: ConnectionInfo
9197defaultRemoteConnectionInfo = RemoteProcessConnectionInfo defaultDatabaseName (createNodeId "127.0.0.1" defaultServerPort)
9298
ProjectM36/Server/EntryPoints.hs+2−1
@@ -7,7 +7,8 @@ import Control.Distributed.Process.ManagedProcess (ProcessReply)
77import Control.Distributed.Process.ManagedProcess.Server (reply)
88import Control.Monad.IO.Class (liftIO)
99import Data.Map
10−import Data.UUID (UUID, nextRandom)
10+import Data.UUID (UUID)
11+import Data.UUID.V4 (nextRandom)
1112
1213handleExecuteRelationalExpr :: Connection -> RelationalExpr -> Process (ProcessReply (Either RelationalError Relation) Connection)
1314handleExecuteRelationalExpr conn expr = do
TutorialD/Interpreter.hs+17−17
@@ -57,28 +57,28 @@ parseTutorialD :: String -> Either ParseError ParsedOperation
5757parseTutorialD inputString = parse interpreterParserP "" inputString
5858
5959--execute the operation and display result
60−evalTutorialD :: C.Connection -> ParsedOperation -> IO (TutorialDOperatorResult)
61−evalTutorialD conn expr = case expr of
60+evalTutorialD :: C.SessionId -> C.Connection -> ParsedOperation -> IO (TutorialDOperatorResult)
61+evalTutorialD sessionId conn expr = case expr of
6262
6363 --this does not pass through the ProjectM36.Client library because the operations
6464 --are specific to the interpreter, though some operations may be of general use in the future
6565 (RODatabaseContextOp execOp) -> do
66− evalRODatabaseContextOp conn execOp
66+ evalRODatabaseContextOp sessionId conn execOp
6767
6868 (DatabaseExprOp execOp) -> do
69− maybeErr <- C.executeDatabaseContextExpr conn execOp
69+ maybeErr <- C.executeDatabaseContextExpr sessionId conn execOp
7070 case maybeErr of
7171 Just err -> barf err
7272 Nothing -> return QuietSuccessResult
7373
7474 (GraphOp execOp) -> do
75− maybeErr <- C.executeGraphExpr conn execOp
75+ maybeErr <- C.executeGraphExpr sessionId conn execOp
7676 case maybeErr of
7777 Just err -> barf err
7878 Nothing -> return QuietSuccessResult
7979
8080 (ROGraphOp execOp) -> do
81− opResult <- evalROGraphOp conn execOp
81+ opResult <- evalROGraphOp sessionId conn execOp
8282 case opResult of
8383 Left err -> barf err
8484 Right rel -> return $ DisplayResult $ showRelation rel
@@ -86,24 +86,24 @@ evalTutorialD conn expr = case expr of
8686 (ImportRelVarOp execOp@(RelVarDataImportOperator relVarName _ _)) -> do
8787 -- collect attributes from relvar name
8888 -- is there a race condition here? The attributes of the relvar may have since changed, no?
89− eImportType <- C.typeForRelationalExpr conn (RelationVariable relVarName)
89+ eImportType <- C.typeForRelationalExpr sessionId conn (RelationVariable relVarName)
9090 case eImportType of
9191 Left err -> barf err
9292 Right importType -> do
9393 exprErr <- evalRelVarDataImportOperator execOp (attributes importType)
9494 case exprErr of
9595 Left err -> barf err
96− Right dbexpr -> evalTutorialD conn (DatabaseExprOp dbexpr)
96+ Right dbexpr -> evalTutorialD sessionId conn (DatabaseExprOp dbexpr)
9797
9898 (ImportDBContextOp execOp) -> do
9999 mDbexprs <- evalDatabaseContextDataImportOperator execOp
100100 case mDbexprs of
101101 Left err -> barf err
102− Right dbexprs -> evalTutorialD conn (DatabaseExprOp dbexprs)
102+ Right dbexprs -> evalTutorialD sessionId conn (DatabaseExprOp dbexprs)
103103
104104 (RelVarExportOp execOp@(RelVarDataExportOperator relExpr _ _)) -> do
105105 --eval relexpr to relation and pass to export function
106− eRel <- C.executeRelationalExpr conn relExpr
106+ eRel <- C.executeRelationalExpr sessionId conn relExpr
107107 case eRel of
108108 Left err -> barf err
109109 Right rel -> do
@@ -114,14 +114,14 @@ evalTutorialD conn expr = case expr of
114114 where
115115 barf err = return $ DisplayErrorResult (T.pack (show err))
116116
117−data InterpreterConfig = LocalInterpreterConfig PersistenceStrategy |
118− RemoteInterpreterConfig C.NodeId C.DatabaseName
117+data InterpreterConfig = LocalInterpreterConfig PersistenceStrategy HeadName|
118+ RemoteInterpreterConfig C.NodeId C.DatabaseName HeadName
119119
120−reprLoop :: InterpreterConfig -> C.Connection -> IO ()
121−reprLoop config conn = do
120+reprLoop :: InterpreterConfig -> C.SessionId -> C.Connection -> IO ()
121+reprLoop config sessionId conn = do
122122 homeDirectory <- getHomeDirectory
123123 let settings = defaultSettings {historyFile = Just (homeDirectory ++ "/.tutd_history")}
124− mHeadName <- C.headName conn
124+ mHeadName <- C.headName sessionId conn
125125 maybeLine <- runInputT settings $ getInputLine (T.unpack (promptText mHeadName))
126126 case maybeLine of
127127 Nothing -> return ()
@@ -130,6 +130,6 @@ reprLoop config conn = do
130130 Left err -> do
131131 displayOpResult $ DisplayErrorResult (T.pack (show err))
132132 Right parsed -> do
133− evald <- evalTutorialD conn parsed
133+ evald <- evalTutorialD sessionId conn parsed
134134 displayOpResult evald
135− reprLoop config conn
135+ reprLoop config sessionId conn
TutorialD/Interpreter/RODatabaseContextOperator.hs+22−20
@@ -68,46 +68,48 @@ roDatabaseContextOperatorP = typeP
6868 <|> quitP
6969
7070--logically, these read-only operations could happen purely, but not if a remote call is required
71−evalRODatabaseContextOp :: C.Connection -> RODatabaseContextOperator -> IO TutorialDOperatorResult
72−evalRODatabaseContextOp conn (ShowRelationType expr) = do
73− res <- C.typeForRelationalExpr conn expr
71+evalRODatabaseContextOp :: C.SessionId -> C.Connection -> RODatabaseContextOperator -> IO TutorialDOperatorResult
72+evalRODatabaseContextOp sessionId conn (ShowRelationType expr) = do
73+ res <- C.typeForRelationalExpr sessionId conn expr
7474 case res of
7575 Left err -> pure $ DisplayErrorResult $ T.pack (show err)
7676 Right rel -> pure $ DisplayResult $ showRelation rel
7777
78−evalRODatabaseContextOp conn (ShowRelation expr) = do
79− res <- C.executeRelationalExpr conn expr
78+evalRODatabaseContextOp sessionId conn (ShowRelation expr) = do
79+ res <- C.executeRelationalExpr sessionId conn expr
8080 case res of
8181 Left err -> pure $ DisplayErrorResult $ T.pack (show err)
8282 Right rel -> pure $ DisplayResult $ showRelation rel
8383
84−evalRODatabaseContextOp conn (PlotRelation expr) = do
85− res <- C.executeRelationalExpr conn expr
84+evalRODatabaseContextOp sessionId conn (PlotRelation expr) = do
85+ res <- C.executeRelationalExpr sessionId conn expr
8686 pure $ case res of
8787 Left err -> DisplayErrorResult $ T.pack (show err)
8888 Right rel -> DisplayIOResult $ do
8989 err <- plotRelation rel
9090 when (isJust err) $ putStrLn (show err)
9191
92−evalRODatabaseContextOp conn (ShowConstraint name) = do
93− incDeps <- C.inclusionDependencies conn
94− pure $ case name of
95− "" -> DisplayResult $ T.pack (show incDeps)
96− depName -> case M.lookup depName incDeps of
97− Nothing -> DisplayErrorResult "No such constraint."
98− Just dep -> DisplayResult $ T.pack (show dep)
92+evalRODatabaseContextOp sessionId conn (ShowConstraint name) = do
93+ eIncDeps <- C.inclusionDependencies sessionId conn
94+ pure $ case eIncDeps of
95+ Left err -> DisplayErrorResult $ T.pack (show err)
96+ Right incDeps -> case name of
97+ "" -> DisplayResult $ T.pack (show incDeps)
98+ depName -> case M.lookup depName incDeps of
99+ Nothing -> DisplayErrorResult "No such constraint."
100+ Just dep -> DisplayResult $ T.pack (show dep)
99101
100−evalRODatabaseContextOp conn (ShowPlan dbExpr) = do
101− plan <- C.planForDatabaseContextExpr conn dbExpr
102+evalRODatabaseContextOp sessionId conn (ShowPlan dbExpr) = do
103+ plan <- C.planForDatabaseContextExpr sessionId conn dbExpr
102104 pure $ case plan of
103105 Left err -> DisplayErrorResult (T.pack (show err))
104106 Right optDbExpr -> DisplayResult $ T.pack (show optDbExpr)
105107
106−evalRODatabaseContextOp _ (Quit) = pure QuitResult
108+evalRODatabaseContextOp _ _ (Quit) = pure QuitResult
107109
108−interpretRODatabaseContextOp :: C.Connection -> String -> IO TutorialDOperatorResult
109−interpretRODatabaseContextOp conn tutdstring = case parse roDatabaseContextOperatorP "" tutdstring of
110+interpretRODatabaseContextOp :: C.SessionId -> C.Connection -> String -> IO TutorialDOperatorResult
111+interpretRODatabaseContextOp sessionId conn tutdstring = case parse roDatabaseContextOperatorP "" tutdstring of
110112 Left err -> pure $ DisplayErrorResult (T.pack (show err))
111− Right parsed -> evalRODatabaseContextOp conn parsed
113+ Right parsed -> evalRODatabaseContextOp sessionId conn parsed
112114
113115
TutorialD/Interpreter/TransactionGraphOperator.hs+2−2
@@ -74,5 +74,5 @@ interpretOps newUUID trans@(DisconnectedTransaction _ context) transGraph instri
7474 Right (newDiscon, newGraph, result) -> (newDiscon, newGraph, result)
7575-}
7676
77−evalROGraphOp :: Connection -> ROTransactionGraphOperator -> IO (Either RelationalError Relation)
78−evalROGraphOp conn ShowGraph = transactionGraphAsRelation conn
77+evalROGraphOp :: SessionId -> Connection -> ROTransactionGraphOperator -> IO (Either RelationalError Relation)
78+evalROGraphOp sessionId conn ShowGraph = transactionGraphAsRelation sessionId conn
TutorialD/tutd.hs+25−8
@@ -7,8 +7,8 @@ import Options.Applicative
77import System.Exit
88
99parseArgs :: Parser InterpreterConfig
10−parseArgs = LocalInterpreterConfig <$> parsePersistenceStrategy <|>
11− RemoteInterpreterConfig <$> parseNodeId <*> parseDatabaseName
10+parseArgs = LocalInterpreterConfig <$> parsePersistenceStrategy <*> parseHeadName <|>
11+ RemoteInterpreterConfig <$> parseNodeId <*> parseDatabaseName <*> parseHeadName
1212
1313parsePersistenceStrategy :: Parser PersistenceStrategy
1414parsePersistenceStrategy = CrashSafePersistence <$> (dbdirOpt <* fsyncOpt) <|>
@@ -24,6 +24,12 @@ parsePersistenceStrategy = CrashSafePersistence <$> (dbdirOpt <* fsyncOpt) <|>
2424 long "fsync" <>
2525 help "Fsync all new transactions.")
2626
27+parseHeadName :: Parser HeadName
28+parseHeadName = option auto (long "head" <>
29+ help "Start session at head name." <>
30+ value "master"
31+ )
32+
2733parseDatabaseName :: Parser DatabaseName
2834parseDatabaseName = strOption (long "database" <>
2935 help "Remote database name")
@@ -43,9 +49,16 @@ opts :: ParserInfo InterpreterConfig
4349opts = info parseArgs idm
4450
4551connectionInfoForConfig :: InterpreterConfig -> ConnectionInfo
46−connectionInfoForConfig (LocalInterpreterConfig pStrategy) = InProcessConnectionInfo pStrategy
47−connectionInfoForConfig (RemoteInterpreterConfig remoteNodeId remoteDBName) = RemoteProcessConnectionInfo remoteDBName remoteNodeId
52+connectionInfoForConfig (LocalInterpreterConfig pStrategy _) = InProcessConnectionInfo pStrategy
53+connectionInfoForConfig (RemoteInterpreterConfig remoteNodeId remoteDBName _) = RemoteProcessConnectionInfo remoteDBName remoteNodeId
54+
55+headNameForConfig :: InterpreterConfig -> HeadName
56+headNameForConfig (LocalInterpreterConfig _ headn) = headn
57+headNameForConfig (RemoteInterpreterConfig _ _ headn) = headn
4858
59+errDie :: String -> IO ()
60+errDie err = hPutStrLn stderr err >> exitFailure
61+
4962main :: IO ()
5063main = do
5164 interpreterConfig <- execParser opts
@@ -53,9 +66,13 @@ main = do
5366 dbconn <- connectProjectM36 connInfo
5467 case dbconn of
5568 Left err -> do
56− hPutStrLn stderr ("Failed to create database connection: " ++ show err)
57− exitFailure
69+ errDie ("Failed to create database connection: " ++ show err)
5870 Right conn -> do
59− _ <- reprLoop interpreterConfig conn
60− return ()
71+ let connHeadName = headNameForConfig interpreterConfig
72+ eSessionId <- createSessionAtHead connHeadName conn
73+ case eSessionId of
74+ Left err -> errDie ("Failed to create database session at \"" ++ show connHeadName ++ "\": " ++ show err)
75+ Right sessionId -> do
76+ _ <- reprLoop interpreterConfig sessionId conn
77+ pure ()
6178
project-m36.cabal+19−15
@@ -129,7 +129,9 @@ Executable tutd
129129 haskeline,
130130 base64-bytestring,
131131 optparse-applicative,
132− attoparsec
132+ attoparsec,
133+ stm-containers,
134+ list-t
133135 Other-Modules: ProjectM36.Error,
134136 ProjectM36.Base,
135137 ProjectM36.RelationalExpression,
@@ -178,7 +180,9 @@ Executable project-m36-server
178180 hashable,
179181 unordered-containers,
180182 vector,
181− http-api-data
183+ http-api-data,
184+ stm-containers,
185+ list-t
182186 Main-Is: ProjectM36/Server/project-m36-server.hs
183187 GHC-Options: -Wall -threaded -rtsopts
184188 GHC-Prof-Options: -fprof-auto -rtsopts -threaded -Wall
@@ -188,7 +192,7 @@ Executable project-m36-server
188192
189193Executable bigrel
190194 Default-Language: Haskell2010
191− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, optparse-applicative
195+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, optparse-applicative, stm-containers
192196 Other-Modules: ProjectM36.Base,
193197 ProjectM36.Relation
194198 ProjectM36.Tuple,
@@ -203,7 +207,7 @@ Test-Suite test-tutoriald
203207 Default-Language: Haskell2010
204208 type: exitcode-stdio-1.0
205209 main-is: test/TutorialD/Interpreter.hs
206− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath
210+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, stm-containers
207211 GHC-Options: -Wall
208212 C-sources: ProjectM36/DirectoryFsync.c
209213
@@ -211,21 +215,21 @@ Test-Suite test-relation
211215 Default-Language: Haskell2010
212216 type: exitcode-stdio-1.0
213217 main-is: test/Relation/Basic.hs
214− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath
218+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, stm-containers
215219 GHC-Options: -Wall
216220
217221Test-Suite test-static-optimizer
218222 Default-Language: Haskell2010
219223 type: exitcode-stdio-1.0
220224 main-is: test/Relation/StaticOptimizer.hs
221− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath
225+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, stm-containers
222226 GHC-Options: -Wall
223227
224228Test-Suite test-transactiongraph-persist
225229 Default-Language: Haskell2010
226230 type: exitcode-stdio-1.0
227231 main-is: test/TransactionGraph/Persist.hs
228− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath
232+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, stm-containers
229233 GHC-Options: -Wall
230234 C-sources: ProjectM36/DirectoryFsync.c
231235
@@ -233,28 +237,28 @@ Test-Suite test-relation-import-csv
233237 Default-Language: Haskell2010
234238 type: exitcode-stdio-1.0
235239 main-is: test/Relation/Import/CSV.hs
236− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath
240+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, stm-containers
237241 GHC-Options: -Wall
238242
239243Test-Suite test-tutoriald-import-tutoriald
240244 Default-Language: Haskell2010
241245 type: exitcode-stdio-1.0
242246 main-is: test/TutorialD/Interpreter/Import/TutorialD.hs
243− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath
247+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, stm-containers
244248 GHC-Options: -Wall
245249
246250Test-Suite test-relation-export-csv
247251 Default-Language: Haskell2010
248252 type: exitcode-stdio-1.0
249253 main-is: test/Relation/Export/CSV.hs
250− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath
254+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, stm-containers
251255 GHC-Options: -Wall
252256
253257Test-Suite test-persistent-driver
254258 Default-Language: Haskell2010
255259 type: exitcode-stdio-1.0
256260 main-is: test/persistent-driver/test.hs
257− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, template-haskell, transformers, aeson, persistent-template, conduit, persistent, either, path-pieces, http-api-data
261+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, template-haskell, transformers, aeson, persistent-template, conduit, persistent, either, path-pieces, http-api-data, stm-containers
258262 GHC-Options: -Wall
259263 C-sources: ProjectM36/DirectoryFsync.c
260264
@@ -262,27 +266,27 @@ benchmark bench
262266 Default-Language: Haskell2010
263267 type: exitcode-stdio-1.0
264268 main-is: benchmark/Relation.hs
265− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, criterion
269+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, criterion, stm-containers
266270 GHC-Options: -Wall -rtsopts
267271
268272Test-Suite test-server
269273 Default-Language: Haskell2010
270274 type: exitcode-stdio-1.0
271275 main-is: test/Server/Main.hs
272− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers
276+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers
273277 GHC-Options: -Wall
274278 C-sources: ProjectM36/DirectoryFsync.c
275279
276280Executable Example-SimpleClient
277281 Default-Language: Haskell2010
278− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers
282+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers
279283 Main-Is: examples/SimpleClient.hs
280284 GHC-Options: -Wall
281285 C-sources: ProjectM36/DirectoryFsync.c
282286
283287Executable Example-PersistClient
284288 Default-Language: Haskell2010
285− Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers
289+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers, stm-containers
286290 Main-Is: examples/PersistClient.hs
287291 GHC-Options: -Wall
288292 C-sources: ProjectM36/DirectoryFsync.c