@@ -1,11 +1,16 @@
11{-# LANGUAGE DeriveAnyClass, DeriveGeneric, ScopedTypeVariables, BangPatterns #-}
2+{-|
3+Module: ProjectM36.Client
4+
5+Client interface to local and remote Project:M36 databases. To get started, connect with 'connectProjectM36', then run some database changes with 'executeDatabaseContextExpr', and issue queries using 'executeRelationalExpr'.
6+-}
27module ProjectM36.Client
38 (ConnectionInfo(..),
49 Connection(..),
510 Port,
611 Hostname,
712 DatabaseName,
8− ConnectionError,
13+ ConnectionError(..),
914 connectProjectM36,
1015 close,
1116 closeRemote_,
@@ -20,7 +25,6 @@ module ProjectM36.Client
2025 typeForRelationalExpr,
2126 inclusionDependencies,
2227 planForDatabaseContextExpr,
23− processTransactionGraphPersistence,
2428 currentSchemaName,
2529 SchemaName,
2630 HeadName,
@@ -166,7 +170,7 @@ data RequestTimeoutException = RequestTimeoutException
166170
167171instance Exception RequestTimeoutException
168172
169−-- | Construct a 'ConnectionInfo' to describe how to make the 'Connection'.
173+-- | Construct a 'ConnectionInfo' to describe how to make the 'Connection'. The database can be run within the current process or running remotely via distributed-process.
170174data ConnectionInfo = InProcessConnectionInfo PersistenceStrategy NotificationCallback [GhcPkgPath]|
171175 RemoteProcessConnectionInfo DatabaseName NodeId NotificationCallback
172176
@@ -183,18 +187,24 @@ data EvaluatedNotification = EvaluatedNotification {
183187 }
184188 deriving(Binary, Eq, Show, Generic)
185189
190+
191+-- | Create a 'NodeId' for use in connecting to a remote server using distributed-process.
186192createNodeId :: Hostname -> Port -> NodeId
187193createNodeId host port = NodeId $ encodeEndPointAddress host (show port) 1
188194
195+-- | Use this for connecting to remote servers on the default port.
189196defaultServerPort :: Port
190197defaultServerPort = 6543
191198
199+-- | Use this for connecting to remote servers with the default database name.
192200defaultDatabaseName :: DatabaseName
193201defaultDatabaseName = "base"
194202
203+-- | Use this for connecting to remote servers with the default head name.
195204defaultHeadName :: HeadName
196205defaultHeadName = "master"
197206
207+-- | Create a connection configuration which connects to the localhost on the default server port and default server database name. The configured notification callback is set to ignore all events.
198208defaultRemoteConnectionInfo :: ConnectionInfo
199209defaultRemoteConnectionInfo = RemoteProcessConnectionInfo defaultDatabaseName (createNodeId "127.0.0.1" defaultServerPort) emptyNotificationCallback
200210
@@ -268,7 +278,7 @@ createScriptSession ghcPkgPaths = do
268278 Left err -> hPutStrLn stderr ("Failed to load scripting engine- scripting disabled: " ++ (show err)) >> pure Nothing --not a fatal error, but the scripting feature must be disabled
269279 Right s -> pure (Just s)
270280
271−-- | To create a 'Connection' to a remote or local database, create a connectionInfo and call 'connectProjectM36'.
281+-- | To create a 'Connection' to a remote or local database, create a 'ConnectionInfo' and call 'connectProjectM36'.
272282connectProjectM36 :: ConnectionInfo -> IO (Either ConnectionError Connection)
273283--create a new in-memory database/transaction graph
274284connectProjectM36 (InProcessConnectionInfo strat notificationCallback ghcPkgPaths) = do
@@ -403,7 +413,7 @@ closeSession :: SessionId -> Connection -> IO ()
403413closeSession sessionId (InProcessConnection conf) = do
404414 atomically $ STMMap.delete sessionId (ipSessions conf)
405415closeSession sessionId conn@(RemoteProcessConnection _) = remoteCall conn (CloseSession sessionId)
406−-- | 'close' cleans up the database access connection. Note that sessions persist even after the connection is closed.
416+-- | 'close' cleans up the database access connection and closes any relevant sockets.
407417close :: Connection -> IO ()
408418close (InProcessConnection conf) = do
409419 atomically $ do
@@ -415,8 +425,6 @@ close (InProcessConnection conf) = do
415425
416426close conn@(RemoteProcessConnection conf) = do
417427 _ <- (remoteCall conn Logout) :: IO Bool
418− --putStrLn ("closing " ++ show (localNodeId (rLocalNode conf)))
419−
420428 closeLocalNode (rLocalNode conf)
421429 closeTransport (rTransport conf)
422430
@@ -490,6 +498,7 @@ sessionAndSchema sessionId sessions = do
490498 Left err -> pure (Left err)
491499 Right schema -> pure (Right (session, schema))
492500
501+-- | Returns the name of the currently selected isomorphic schema.
493502currentSchemaName :: SessionId -> Connection -> IO (Either RelationalError SchemaName)
494503currentSchemaName sessionId (InProcessConnection conf) = atomically $ do
495504 let sessions = ipSessions conf
@@ -499,6 +508,7 @@ currentSchemaName sessionId (InProcessConnection conf) = atomically $ do
499508 Right session -> pure (Right (Sess.schemaName session))
500509currentSchemaName sessionId conn@(RemoteProcessConnection _) = remoteCall conn (RetrieveCurrentSchemaName sessionId)
501510
511+-- | Switch to the named isomorphic schema.
502512setCurrentSchemaName :: SessionId -> Connection -> SchemaName -> IO (Either RelationalError ())
503513setCurrentSchemaName sessionId (InProcessConnection conf) sname = atomically $ do
504514 let sessions = ipSessions conf
@@ -571,7 +581,7 @@ autoMergeToHead sessionId (InProcessConnection conf) strat headName' = do
571581 Right (discon', graph') -> pure (Right (discon', graph', True))
572582autoMergeToHead sessionId conn@(RemoteProcessConnection _) strat headName' = remoteCall conn (ExecuteAutoMergeToHead sessionId strat headName')
573583
574−-- | Execute a database context IO-monad-based expression for the given session and connection. `DatabaseContextIOExpr` modify the DatabaseContext but cannot be purely implemented.
584+-- | Execute a database context IO-monad-based expression for the given session and connection. `DatabaseContextIOExpr`s modify the DatabaseContext but cannot be purely implemented.
575585--this is almost completely identical to executeDatabaseContextExpr above
576586executeDatabaseContextIOExpr :: SessionId -> Connection -> DatabaseContextIOExpr -> IO (Either RelationalError ())
577587executeDatabaseContextIOExpr sessionId (InProcessConnection conf) expr = excEither $ do
@@ -617,6 +627,7 @@ executeCommitExprSTM_ oldContext newContext nodes = do
617627 pure (evaldNots, nodes)
618628
619629-- | Execute a transaction graph expression in the context of the session and connection. Transaction graph operators modify the transaction graph state.
630+
620631-- OPTIMIZATION OPPORTUNITY: no locks are required to write new transaction data, only to update the transaction graph id file
621632-- if writing data is re-entrant, we may be able to use unsafeIOtoSTM
622633-- perhaps keep hash of data file instead of checking if our head was updated on every write
@@ -718,6 +729,7 @@ executeTransGraphRelationalExpr _ (InProcessConnection conf) tgraphExpr = excEit
718729 Right rel -> pure (force (Right rel))
719730executeTransGraphRelationalExpr sessionId conn@(RemoteProcessConnection _) tgraphExpr = remoteCall conn (ExecuteTransGraphRelationalExpr sessionId tgraphExpr)
720731
732+-- | Schema expressions manipulate the isomorphic schemas for the current 'DatabaseContext'.
721733executeSchemaExpr :: SessionId -> Connection -> Schema.SchemaExpr -> IO (Either RelationalError ())
722734executeSchemaExpr sessionId (InProcessConnection conf) schemaExpr = atomically $ do
723735 let sessions = ipSessions conf
@@ -737,7 +749,7 @@ executeSchemaExpr sessionId (InProcessConnection conf) schemaExpr = atomically $
737749 pure (Right ())
738750executeSchemaExpr sessionId conn@(RemoteProcessConnection _) schemaExpr = remoteCall conn (ExecuteSchemaExpr sessionId schemaExpr)
739751
740−-- | After modifying a session, 'commit' the transaction to the transaction graph at the head which the session is referencing. This will also trigger checks for any notifications which need to be propagated.
752+-- | After modifying a 'DatabaseContext', 'commit' the transaction to the transaction graph at the head which the session is referencing. This will also trigger checks for any notifications which need to be propagated.
741753commit :: SessionId -> Connection -> IO (Either RelationalError ())
742754commit sessionId conn@(InProcessConnection _) = executeGraphExpr sessionId conn Commit
743755commit sessionId conn@(RemoteProcessConnection _) = remoteCall conn (ExecuteGraphExpr sessionId Commit)
@@ -748,11 +760,12 @@ sendNotifications pids localNode nots = mapM_ sendNots pids
748760 sendNots remoteClientPid = do
749761 when (not (M.null nots)) $ runProcess localNode $ send remoteClientPid (NotificationMessage nots)
750762
751−-- | Discard any changes made in the current session. This resets the disconnected transaction to reference the original database context of the parent transaction and is a very cheap operation.
763+-- | Discard any changes made in the current 'Session' and 'DatabaseContext'. This resets the disconnected transaction to reference the original database context of the parent transaction and is a very cheap operation.
752764rollback :: SessionId -> Connection -> IO (Either RelationalError ())
753765rollback sessionId conn@(InProcessConnection _) = executeGraphExpr sessionId conn Rollback
754766rollback sessionId conn@(RemoteProcessConnection _) = remoteCall conn (ExecuteGraphExpr sessionId Rollback)
755767
768+-- | Write the transaction graph to disk. This function can be used to incrementally write new transactions to disk.
756769processTransactionGraphPersistence :: PersistenceStrategy -> TransactionGraph -> IO ()
757770processTransactionGraphPersistence NoPersistence _ = pure ()
758771processTransactionGraphPersistence (MinimalPersistence dbdir) graph = transactionGraphPersist NoDiskSync dbdir graph >> pure ()
@@ -818,10 +831,10 @@ planForDatabaseContextExpr sessionId (InProcessConnection conf) dbExpr = do
818831planForDatabaseContextExpr sessionId conn@(RemoteProcessConnection _) dbExpr = remoteCall conn (RetrievePlanForDatabaseContextExpr sessionId dbExpr)
819832
820833-- | Return a relation which represents the current state of the global transaction graph. The attributes are
821−-- * current- boolean attribute representing whether or not the current session references this transaction
822−-- * head- text attribute which is a non-empty 'HeadName' iff the transaction references a head.
823−-- * id- id attribute of the transaction
824−-- * parents- a relation-valued attribute which contains a relation of transaction ids which are parent transaction to the transaction
834+-- * current- boolean attribute representing whether or not the current session references this transaction
835+-- * head- text attribute which is a non-empty 'HeadName' iff the transaction references a head.
836+-- * id- id attribute of the transaction
837+-- * parents- a relation-valued attribute which contains a relation of transaction ids which are parent transaction to the transaction
825838transactionGraphAsRelation :: SessionId -> Connection -> IO (Either RelationalError Relation)
826839transactionGraphAsRelation sessionId (InProcessConnection conf) = do
827840 let sessions = ipSessions conf
@@ -836,6 +849,7 @@ transactionGraphAsRelation sessionId (InProcessConnection conf) = do
836849
837850transactionGraphAsRelation sessionId conn@(RemoteProcessConnection _) = remoteCall conn (RetrieveTransactionGraph sessionId)
838851
852+-- | Returns the names and types of the relation variables in the current 'Session'.
839853relationVariablesAsRelation :: SessionId -> Connection -> IO (Either RelationalError Relation)
840854relationVariablesAsRelation sessionId (InProcessConnection conf) = do
841855 let sessions = ipSessions conf
@@ -885,6 +899,7 @@ headName sessionId (InProcessConnection conf) = do
885899 atomically (headNameSTM_ sessionId sessions graphTvar)
886900headName sessionId conn@(RemoteProcessConnection _) = remoteCall conn (ExecuteHeadName sessionId)
887901
902+-- | Returns a listing of all available atom types.
888903atomTypesAsRelation :: SessionId -> Connection -> IO (Either RelationalError Relation)
889904atomTypesAsRelation sessionId (InProcessConnection conf) = do
890905 let sessions = ipSessions conf
@@ -1008,4 +1023,4 @@ writeDisconAndGraph_ graphTvar sessionId session sessions discon graph = do
10081023 writeTVar graphTvar graph
10091024 let newSession = Session discon (Sess.schemaName session)
10101025 STMMap.insert newSession sessionId sessions
1011−-}
1026+-}