module RewindableIndex.Index.VSqlite
  ( -- * API
    SqliteIndex
  , new
  , newBoxed
  , S.insert
  , S.insertL
  , S.size
  , S.rewind
  , S.getEvents
  , S.getBuffer
  , S.handle
  , S.storage
  ) where

import Control.Monad.Primitive (PrimState)
import Data.Vector qualified as V
import Data.Vector.Generic qualified as VG
import Data.Vector.Generic.Mutable qualified as VGM
import Database.SQLite.Simple (Connection, execute_, open)

import RewindableIndex.Index.VSplit (SplitIndex (SplitIndex), Storage (Storage))
import RewindableIndex.Index.VSplit qualified as S

type SqliteIndex e n q r = SplitIndex IO Connection V.Vector e n q r

new
  :: (SqliteIndex e n q r -> q -> [e] -> IO r)
  -> (SqliteIndex e n q r -> IO ())
  -> (SqliteIndex e n q r -> e -> IO [n])
  -> Int
  -> FilePath
  -> (VG.Mutable V.Vector) (PrimState IO) e
  -> IO (Maybe (SqliteIndex e n q r))
new :: (SqliteIndex e n q r -> q -> [e] -> IO r)
-> (SqliteIndex e n q r -> IO ())
-> (SqliteIndex e n q r -> e -> IO [n])
-> Int
-> FilePath
-> Mutable Vector (PrimState IO) e
-> IO (Maybe (SqliteIndex e n q r))
new SqliteIndex e n q r -> q -> [e] -> IO r
fquery SqliteIndex e n q r -> IO ()
fstore SqliteIndex e n q r -> e -> IO [n]
foninsert Int
k' FilePath
db Mutable Vector (PrimState IO) e
vector
  | Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 = Maybe (SqliteIndex e n q r) -> IO (Maybe (SqliteIndex e n q r))
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (SqliteIndex e n q r)
forall a. Maybe a
Nothing
  | Bool
otherwise  = do
    Connection
connection <- FilePath -> IO Connection
open FilePath
db
    Connection -> Query -> IO ()
execute_ Connection
connection Query
"PRAGMA journal_mode=WAL"

    Maybe (SqliteIndex e n q r) -> IO (Maybe (SqliteIndex e n q r))
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe (SqliteIndex e n q r) -> IO (Maybe (SqliteIndex e n q r)))
-> (SqliteIndex e n q r -> Maybe (SqliteIndex e n q r))
-> SqliteIndex e n q r
-> IO (Maybe (SqliteIndex e n q r))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SqliteIndex e n q r -> Maybe (SqliteIndex e n q r)
forall a. a -> Maybe a
Just (SqliteIndex e n q r -> IO (Maybe (SqliteIndex e n q r)))
-> SqliteIndex e n q r -> IO (Maybe (SqliteIndex e n q r))
forall a b. (a -> b) -> a -> b
$ SplitIndex :: forall (m :: * -> *) h (v :: * -> *) e n q r.
h
-> Storage v m e
-> [n]
-> (SplitIndex m h v e n q r -> m ())
-> (SplitIndex m h v e n q r -> q -> [e] -> m r)
-> (SplitIndex m h v e n q r -> e -> m [n])
-> SplitIndex m h v e n q r
SplitIndex
      { _handle :: Connection
S._handle        = Connection
connection
      , _storage :: Storage Vector IO e
S._storage = Storage :: forall (v :: * -> *) (m :: * -> *) e.
Mutable v (PrimState m) e
-> Int -> Int -> Int -> Int -> Storage v m e
Storage { _events :: Mutable Vector (PrimState IO) e
S._events = Mutable Vector (PrimState IO) e
vector
                             , _cursor :: Int
S._cursor = Int
0
                             , _eSize :: Int
S._eSize  = Int
0
                             , _bSize :: Int
S._bSize  = Int
0
                             , _k :: Int
S._k      = Int
k'
                             }
      , _notifications :: [n]
S._notifications = []
      , _store :: SqliteIndex e n q r -> IO ()
S._store         = SqliteIndex e n q r -> IO ()
fstore
      , _query :: SqliteIndex e n q r -> q -> [e] -> IO r
S._query         = SqliteIndex e n q r -> q -> [e] -> IO r
fquery
      , _onInsert :: SqliteIndex e n q r -> e -> IO [n]
S._onInsert      = SqliteIndex e n q r -> e -> IO [n]
foninsert
      }

type BoxedIndex e n q r = SqliteIndex e n q r

newBoxed
  :: (BoxedIndex e n q r -> q -> [e] -> IO r)
  -> (BoxedIndex e n q r -> IO ())
  -> (BoxedIndex e n q r -> e -> IO [n])
  -> Int
  -> Int
  -> FilePath
  -> IO (Maybe (BoxedIndex e n q r))
newBoxed :: (BoxedIndex e n q r -> q -> [e] -> IO r)
-> (BoxedIndex e n q r -> IO ())
-> (BoxedIndex e n q r -> e -> IO [n])
-> Int
-> Int
-> FilePath
-> IO (Maybe (BoxedIndex e n q r))
newBoxed BoxedIndex e n q r -> q -> [e] -> IO r
query' BoxedIndex e n q r -> IO ()
store' BoxedIndex e n q r -> e -> IO [n]
onInsert' Int
k' Int
size' FilePath
dbPath
  | Int
k' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0 Bool -> Bool -> Bool
|| Int
size' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = Maybe (BoxedIndex e n q r) -> IO (Maybe (BoxedIndex e n q r))
forall (f :: * -> *) a. Applicative f => a -> f a
pure Maybe (BoxedIndex e n q r)
forall a. Maybe a
Nothing
  | Bool
otherwise = do
    MVector RealWorld e
v <- Int -> IO (MVector (PrimState IO) e)
forall (m :: * -> *) (v :: * -> * -> *) a.
(PrimMonad m, MVector v a) =>
Int -> m (v (PrimState m) a)
VGM.new (Int
k' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
size')
    (BoxedIndex e n q r -> q -> [e] -> IO r)
-> (BoxedIndex e n q r -> IO ())
-> (BoxedIndex e n q r -> e -> IO [n])
-> Int
-> FilePath
-> Mutable Vector (PrimState IO) e
-> IO (Maybe (BoxedIndex e n q r))
forall e n q r.
(SqliteIndex e n q r -> q -> [e] -> IO r)
-> (SqliteIndex e n q r -> IO ())
-> (SqliteIndex e n q r -> e -> IO [n])
-> Int
-> FilePath
-> Mutable Vector (PrimState IO) e
-> IO (Maybe (SqliteIndex e n q r))
new BoxedIndex e n q r -> q -> [e] -> IO r
query' BoxedIndex e n q r -> IO ()
store' BoxedIndex e n q r -> e -> IO [n]
onInsert' Int
k' FilePath
dbPath MVector RealWorld e
Mutable Vector (PrimState IO) e
v