{-# OPTIONS_GHC -fno-warn-orphans #-} module Fixme.State ( evolve , withState , insertFixme , selectFixme , insertCommit , selectCommit , newCommit ) where import Fixme.Prelude import Fixme.Types import Fixme.Config import HBS2.System.Dir import Data.Config.Suckless import DBPipe.SQLite import Data.HashMap.Strict qualified as HM import Text.InterpolatedString.Perl6 (qc) import Data.Maybe instance ToField HashRef where toField x = toField $ show $ pretty x instance FromField HashRef where fromField = fmap (fromString @HashRef) . fromField @String evolve :: FixmePerks m => FixmeM m () evolve = do dbpath <- localDBPath debug $ "evolve" <+> pretty dbpath mkdir (takeDirectory dbpath) db <- newDBPipeEnv dbPipeOptsDef dbpath withDB db do createTables withState :: forall m a . (FixmePerks m, MonadReader FixmeEnv m) => DBPipeM m a -> m a withState what = do db <- asks fixmeEnvDb withDB db what createTables :: FixmePerks m => DBPipeM m () createTables = do -- тут все таблицы будут называться с префиксом -- fixme, что бы может быть можно было встроить -- в другую бд, если вдруг понадобится ddl [qc| create table if not exists fixmecommit ( hash text not null , primary key (hash) ) |] ddl [qc| create table if not exists fixme ( id text not null , ts integer , fixme blob not null , primary key (id) ) |] ddl [qc| create table if not exists fixmedeleted ( id text not null , ts integer not null , deleted bool not null , primary key (id,ts) ) |] ddl [qc| create table if not exists fixmerel ( origin text not null , related text not null , ts integer not null , reason text not null , primary key (origin,related,ts) ) |] ddl [qc| create table if not exists fixmeattr ( fixme text not null , ts integer null , name text not null , value text , primary key (fixme,ts,name) ) |] ddl [qc| drop view if exists fixmeattrview |] ddl [qc| create view fixmeattrview as with ranked as ( select fixme, name, value, row_number() over (partition by fixme, name order by ts desc nulls first) as rn from fixmeattr ) select fixme, name, value from ranked where rn = 1; |] insertCommit :: FixmePerks m => GitHash -> DBPipeM m () insertCommit gh = do insert [qc| insert into fixmecommit (hash) values(?) on conflict (hash) do nothing |] (Only gh) selectCommit :: FixmePerks m => GitHash -> DBPipeM m (Maybe GitHash) selectCommit gh = do select [qc|select hash from fixmecommit where hash = ?|] (Only gh) <&> fmap fromOnly . listToMaybe newCommit :: (FixmePerks m, MonadReader FixmeEnv m) => GitHash -> m Bool newCommit gh = isNothing <$> withState (selectCommit gh) insertFixme :: FixmePerks m => Fixme -> DBPipeM m () insertFixme fx@Fixme{..} = do let fixme = serialise fx let fxId = hashObject @HbSync fixme & HashRef insert [qc|insert into fixme (id, ts, fixme) values (?,?,?) on conflict(id) do nothing |] (fxId, fixmeTs, fixme) for_ (HM.toList fixmeAttr) $ \(n,v) -> do insert [qc| insert into fixmeattr(fixme,ts,name,value) values (?,?,?,?) on conflict (fixme,ts,name) do update set value = excluded.value |] (fxId, fixmeTs, n, v) insert [qc| insert into fixmeattr(fixme,ts,name,value) values (?,?,?,?) on conflict (fixme,ts,name) do update set value = excluded.value |] (fxId, fixmeTs, "fixme-tag", fixmeTag) insert [qc| insert into fixmeattr(fixme,ts,name,value) values (?,?,?,?) on conflict (fixme,ts,name) do update set value = excluded.value |] (fxId, fixmeTs, "fixme-title", fixmeTitle) data SelectPredicate = All class HasPredicate a where predicate :: a -> SelectPredicate instance HasPredicate () where predicate = const All selectFixme :: (FixmePerks m, HasPredicate a) => a -> FixmeM m [Fixme] selectFixme _ = do pure mempty