0 | module Oracle.Connection
 1 |
 2 | import Control.Monad.Elin
 3 | import Control.Monad.MCancel
 4 | import Data.Linear.Ref1
 5 | import Oracle.Error
 6 | import Oracle.FFI.Connection
 7 | import Oracle.Internal.Pointer
 8 | import Oracle.Types.ConnectInfo
 9 | import Oracle.Types.Error
10 |
11 | ||| Establish a connection to Oracle.
12 | |||
13 | export
14 | connect : ConnectInfo -> IO (Either OracleError Connection)
15 | connect cfg = do
16 |   ptr <- primIO (prim__connect cfg.username cfg.password (connectString cfg))
17 |   case prim__nullAnyPtr ptr == 1 of
18 |     True  => do
19 |       lasterr <- getLastError
20 |       pure (Left lasterr)
21 |     False =>
22 |       pure (Right (MkConnection ptr))
23 |   where
24 |     connectString : ConnectInfo -> String
25 |     connectString cfg =
26 |       cfg.host      ++
27 |       ":"           ++
28 |       show cfg.port ++
29 |       "/"           ++
30 |       cfg.service
31 |
32 | ||| Close an Oracle connection.
33 | |||
34 | export
35 | disconnect : Connection -> IO ()
36 | disconnect conn =
37 |   primIO (prim__disconnect conn.ptr)
38 |
39 | ||| Establish a connection, execute an action, and guarantee that the connection is closed afterwards.
40 | |||
41 | ||| This function provides safe resource management for Oracle connections, and should generally be preferred over calling `connect` and `disconnect` manually.
42 | |||
43 | ||| The connection is:
44 | ||| 1. Established.
45 | ||| 2. Passed to the supplied action.
46 | ||| 3. Disconnected regardless of whether the action succeeds or fails.
47 | |||
48 | ||| Example:
49 | |||
50 | ||| ```idris
51 | ||| withConnection cfg $ \conn =>
52 | |||   query_ conn
53 | |||          "select * from employees"
54 | |||          []
55 | ||| ```
56 | |||
57 | export
58 | withConnection : ConnectInfo -> (Connection -> IO (Either OracleError a)) -> IO (Either OracleError a)
59 | withConnection cfg action = do
60 |   result <- runElinIO (withConnection' cfg)
61 |   case result of
62 |     Right value =>
63 |       case value of
64 |         Left err     =>
65 |           pure (Left err)
66 |         Right value' =>
67 |           pure (Right value')
68 |     Left err    =>
69 |       assert_total $ idris_crash "Oracle.Connection.withConnection: \{show err}"
70 |   where
71 |     acquire : ConnectInfo -> F1 World (Either OracleError Connection)
72 |     acquire cfg = do
73 |       ioToF1 (connect cfg)
74 |     use : Either OracleError Connection -> F1 World (Either OracleError a)
75 |     use conn =
76 |       case conn of
77 |         Left err    =>
78 |           ioToF1 (pure (Left err))
79 |         Right conn' => 
80 |           ioToF1 (action conn')
81 |     release : Either OracleError Connection -> F1' World
82 |     release conn =
83 |       case conn of
84 |         Left err    =>
85 |           ioToF1 (pure ())
86 |         Right conn' =>
87 |           ioToF1 (disconnect conn')
88 |     withConnection' : ConnectInfo -> Elin World [] (Either OracleError a)
89 |     withConnection' cfg =
90 |       bracket
91 |         (runIO (acquire cfg))
92 |         (\conn => runIO (use conn))
93 |         (\conn => runIO (release conn))
94 |