1+ {-# LANGUAGE ApplicativeDo #-}
12{-# LANGUAGE BlockArguments #-}
23{-# LANGUAGE ConstraintKinds #-}
34{-# LANGUAGE FlexibleContexts #-}
45{-# LANGUAGE LambdaCase #-}
56{-# LANGUAGE RankNTypes #-}
67{-# LANGUAGE ScopedTypeVariables #-}
8+ {-# LANGUAGE TypeApplications #-}
9+ {-# LANGUAGE ViewPatterns #-}
710
811module U.Codebase.Sqlite.Operations where
912
@@ -23,6 +26,7 @@ import qualified Data.Foldable as Foldable
2326import Data.Functor (void , (<&>) )
2427import Data.Map (Map )
2528import qualified Data.Map as Map
29+ import qualified Data.Map.Merge.Lazy as Map
2630import Data.Maybe (isJust )
2731import Data.Sequence (Seq )
2832import qualified Data.Sequence as Seq
@@ -31,35 +35,59 @@ import qualified Data.Set as Set
3135import Data.Text (Text )
3236import qualified Data.Vector as Vector
3337import Data.Word (Word64 )
38+ import qualified U.Codebase.Branch as C
39+ import qualified U.Codebase.Branch as C.Branch
3440import U.Codebase.Decl (ConstructorId )
3541import qualified U.Codebase.Decl as C
3642import qualified U.Codebase.Decl as C.Decl
37- import U.Codebase.HashTags (CausalHash (.. ), BranchHash (.. ))
43+ import U.Codebase.HashTags (BranchHash ( .. ), CausalHash (.. ), PatchHash (.. ))
3844import qualified U.Codebase.Reference as C
3945import qualified U.Codebase.Reference as C.Reference
46+ import qualified U.Codebase.Referent as C
4047import qualified U.Codebase.Referent as C.Referent
4148import U.Codebase.ShortHash (ShortBranchHash (ShortBranchHash ))
49+ import qualified U.Codebase.Sqlite.Branch.Diff as S.Branch
50+ import qualified U.Codebase.Sqlite.Branch.Diff as S.Branch.Diff
51+ import qualified U.Codebase.Sqlite.Branch.Diff as S.BranchDiff
52+ import qualified U.Codebase.Sqlite.Branch.Format as S
53+ import qualified U.Codebase.Sqlite.Branch.Format as S.BranchFormat
54+ import qualified U.Codebase.Sqlite.Branch.Full as S
55+ import qualified U.Codebase.Sqlite.Branch.Full as S.Branch.Full
56+ import qualified U.Codebase.Sqlite.Branch.MetadataSet as S
57+ import qualified U.Codebase.Sqlite.Branch.MetadataSet as S.MetadataSet
4258import qualified U.Codebase.Sqlite.DbId as Db
4359import qualified U.Codebase.Sqlite.Decl.Format as S.Decl
4460import U.Codebase.Sqlite.LocalIds (LocalIds , LocalIds' (.. ), WatchLocalIds )
4561import qualified U.Codebase.Sqlite.LocalIds as LocalIds
4662import qualified U.Codebase.Sqlite.ObjectType as OT
63+ import qualified U.Codebase.Sqlite.Patch.Diff as S
64+ import qualified U.Codebase.Sqlite.Patch.Format as S.PatchFormat
65+ import qualified U.Codebase.Sqlite.Patch.Full as S
66+ import qualified U.Codebase.Sqlite.Patch.TermEdit as S
67+ import qualified U.Codebase.Sqlite.Patch.TermEdit as S.TermEdit
68+ import qualified U.Codebase.Sqlite.Patch.TypeEdit as S
69+ import qualified U.Codebase.Sqlite.Patch.TypeEdit as S.TypeEdit
4770import U.Codebase.Sqlite.Queries (DB )
4871import qualified U.Codebase.Sqlite.Queries as Q
4972import qualified U.Codebase.Sqlite.Reference as S
5073import qualified U.Codebase.Sqlite.Reference as S.Reference
74+ import qualified U.Codebase.Sqlite.Referent as S
5175import qualified U.Codebase.Sqlite.Serialization as S
5276import U.Codebase.Sqlite.Symbol (Symbol )
5377import qualified U.Codebase.Sqlite.Term.Format as S.Term
5478import qualified U.Codebase.Term as C
5579import qualified U.Codebase.Term as C.Term
80+ import qualified U.Codebase.TermEdit as C
81+ import qualified U.Codebase.TermEdit as C.TermEdit
5682import qualified U.Codebase.Type as C.Type
83+ import qualified U.Codebase.TypeEdit as C
84+ import qualified U.Codebase.TypeEdit as C.TypeEdit
5785import U.Codebase.WatchKind (WatchKind )
5886import qualified U.Core.ABT as ABT
5987import U.Util.Base32Hex (Base32Hex )
6088import qualified U.Util.Hash as H
6189import qualified U.Util.Monoid as Monoid
62- import U.Util.Serialization (Get , getFromBytes )
90+ import U.Util.Serialization (Get )
6391import qualified U.Util.Serialization as S
6492
6593type Err m = MonadError Error m
@@ -72,6 +100,10 @@ data DecodeError
72100 = ErrTermElement Word64
73101 | ErrDeclElement Word64
74102 | ErrFramedArrayLen
103+ | ErrTypeOfTerm C.Reference. Id
104+ | ErrWatch WatchKind C.Reference. Id
105+ | ErrBranch Db. BranchObjectId
106+ | ErrPatch Db. PatchObjectId
75107 deriving (Show )
76108
77109data Error
@@ -118,6 +150,31 @@ c2sReferenceId = C.Reference.idH hashToObjectId
118150s2cReferenceId :: EDB m => S.Reference. Id -> m C.Reference. Id
119151s2cReferenceId = C.Reference. idH loadHashByObjectId
120152
153+ s2cReferent :: EDB m => S. Referent -> m C. Referent
154+ s2cReferent = bitraverse s2cReference s2cReference
155+
156+ s2cTermEdit :: EDB m => S. TermEdit -> m C. TermEdit
157+ s2cTermEdit = \ case
158+ S.TermEdit. Replace r t -> C.TermEdit. Replace <$> s2cReference r <*> pure (s2cTyping t)
159+ S.TermEdit. Deprecate -> pure C.TermEdit. Deprecate
160+
161+ s2cTyping :: S.TermEdit. Typing -> C.TermEdit. Typing
162+ s2cTyping = \ case
163+ S.TermEdit. Same -> C.TermEdit. Same
164+ S.TermEdit. Subtype -> C.TermEdit. Subtype
165+ S.TermEdit. Different -> C.TermEdit. Different
166+
167+ s2cTypeEdit :: EDB m => S. TypeEdit -> m C. TypeEdit
168+ s2cTypeEdit = \ case
169+ S.TypeEdit. Replace r -> C.TypeEdit. Replace <$> s2cReference r
170+ S.TypeEdit. Deprecate -> pure C.TypeEdit. Deprecate
171+
172+ s2cBranch :: EDB m => S. Branch -> m (C. Branch m )
173+ s2cBranch = error " todo"
174+
175+ s2cPatch :: EDB m => S. Patch -> m C. Patch
176+ s2cPatch = error " todo"
177+
121178lookupTextId :: DB m => Text -> MaybeT m Db. TextId
122179lookupTextId = m Q. loadText
123180
@@ -350,7 +407,7 @@ loadTypeOfTermByTermReference r = do
350407 -- load "type of term" blob for the reference
351408 bytes <- m' " Q.loadTypeOfTerm" Q. loadTypeOfTerm r'
352409 -- deserialize the blob into the type
353- typ <- m' " getTypeFromBytes " ( fmap pure $ getFromBytes $ S. getType S. getReference) bytes
410+ typ <- getFromBytesOr ( ErrTypeOfTerm r) ( S. getType S. getReference) bytes
354411 -- convert the result type by looking up db ids
355412 C.Type. rtraverse s2cReference typ
356413
@@ -384,7 +441,7 @@ loadWatch :: EDB m => WatchKind -> C.Reference.Id -> MaybeT m (C.Term Symbol)
384441loadWatch k r =
385442 C.Reference. idH Q. saveHashHash r
386443 >>= MaybeT . Q. loadWatch k
387- >>= MaybeT . pure . getFromBytes (S. getPair S. getLocalIds S. getTermElement)
444+ >>= getFromBytesOr ( ErrWatch k r) (S. getPair S. getLocalIds S. getTermElement)
388445 >>= uncurry s2cTerm
389446
390447saveWatch :: EDB m => WatchKind -> C.Reference. Id -> C. Term Symbol -> m ()
@@ -460,7 +517,165 @@ componentByObjectId id = do
460517 len <- (liftQ . Q. loadObjectById) id >>= decodeComponentLengthOnly
461518 pure [C.Reference. Id id i | i <- [0 .. len - 1 ]]
462519
463- -- loadBranchById :: DB m => Db.BranchId -> m C.Branch
520+ loadBranchByObjectId :: EDB m => Db. BranchObjectId -> m (C. Branch m )
521+ loadBranchByObjectId id = do
522+ deserializeBranchObject id >>= \ case
523+ S.BranchFormat. Full f -> doFull f
524+ S.BranchFormat. Diff r d -> doDiff r [d]
525+ where
526+ deserializeBranchObject :: EDB m => Db. BranchObjectId -> m S. BranchFormat
527+ deserializeBranchObject id =
528+ (liftQ . Q. loadObjectById) (Db. unBranchObjectId id )
529+ >>= getFromBytesOr (ErrBranch id ) S. getBranchFormat
530+ deserializePatchObject id =
531+ (liftQ . Q. loadObjectById) (Db. unPatchObjectId id )
532+ >>= getFromBytesOr (ErrPatch id ) S. getPatchFormat
533+ doFull :: EDB m => S.Branch.Full. Branch -> m (C. Branch m )
534+ doFull (S.Branch.Full. Branch tms tps patches children) =
535+ C. Branch
536+ <$> doTerms tms
537+ <*> doTypes tps
538+ <*> doPatches patches
539+ <*> doChildren children
540+ where
541+ bitraverseMap :: (Applicative f , Ord b ) => (a -> f b ) -> (c -> f d ) -> Map a c -> f (Map b d )
542+ bitraverseMap f g = fmap Map. fromList . traverse (bitraverse f g) . Map. toList
543+ traverseSet :: (Applicative f , Ord b ) => (a -> f b ) -> Set a -> f (Set b )
544+ traverseSet f = fmap Set. fromList . traverse f . Set. toList
545+ -- is there a way to make these tidier?
546+ doTerms :: forall m . EDB m => Map Db. TextId (Map S. Referent S. MetadataSetFormat ) -> m (Map C.Branch. NameSegment (Map C. Referent (m C.Branch. MdValues )))
547+ doTerms =
548+ bitraverseMap
549+ (fmap C.Branch. NameSegment . loadTextById)
550+ ( bitraverseMap s2cReferent \ case
551+ S.MetadataSet. Inline rs -> pure $ C.Branch. MdValues <$> traverseSet s2cReference rs
552+ )
553+ doTypes :: forall m . EDB m => Map Db. TextId (Map S. Reference S. MetadataSetFormat ) -> m (Map C.Branch. NameSegment (Map C. Reference (m C.Branch. MdValues )))
554+ doTypes =
555+ bitraverseMap
556+ (fmap C.Branch. NameSegment . loadTextById)
557+ ( bitraverseMap s2cReference \ case
558+ S.MetadataSet. Inline rs -> pure $ C.Branch. MdValues <$> traverseSet s2cReference rs
559+ )
560+ doPatches :: forall m . EDB m => Map Db. TextId Db. PatchObjectId -> m (Map C.Branch. NameSegment (PatchHash , m C. Patch ))
561+ doPatches = bitraverseMap (fmap C.Branch. NameSegment . loadTextById) \ patchId -> do
562+ h <- PatchHash <$> loadHashByObjectId (Db. unPatchObjectId patchId)
563+ let patch :: m C. Patch
564+ patch = do
565+ deserializePatchObject patchId >>= \ case
566+ S.PatchFormat. Full (S. Patch termEdits typeEdits) ->
567+ C. Patch <$> bitraverseMap s2cReferent (traverseSet s2cTermEdit) termEdits <*> bitraverseMap s2cReference (traverseSet s2cTypeEdit) typeEdits
568+ S.PatchFormat. Diff ref d -> doDiff ref [d]
569+ doDiff ref ds =
570+ deserializePatchObject ref >>= \ case
571+ S.PatchFormat. Full f -> s2cPatch (joinFull f ds)
572+ S.PatchFormat. Diff ref' d' -> doDiff ref' (d' : ds)
573+ joinFull f [] = f
574+ joinFull (S. Patch termEdits typeEdits) (S. PatchDiff addedTermEdits addedTypeEdits removedTermEdits removedTypeEdits : ds) = joinFull f' ds
575+ where
576+ f' = S. Patch (addRemove addedTermEdits removedTermEdits termEdits) (addRemove addedTypeEdits removedTypeEdits typeEdits)
577+ addRemove :: (Ord a , Ord b ) => Map a (Set b ) -> Map a (Set b ) -> Map a (Set b ) -> Map a (Set b )
578+ addRemove add del src =
579+ (Map. unionWith (<>) add (Map. differenceWith remove src del))
580+ remove :: Ord b => Set b -> Set b -> Maybe (Set b )
581+ remove src del =
582+ let diff = Set. difference src del
583+ in if diff == mempty then Nothing else Just diff
584+ pure (h, patch)
585+
586+ doChildren :: EDB m => Map Db. TextId Db. BranchObjectId -> m (Map C.Branch. NameSegment (m (C. Branch m )))
587+ doChildren = bitraverseMap (fmap C. NameSegment . loadTextById) (pure . loadBranchByObjectId)
588+ doDiff :: EDB m => Db. BranchObjectId -> [S.Branch. Diff ] -> m (C. Branch m )
589+ doDiff ref ds =
590+ deserializeBranchObject ref >>= \ case
591+ S.BranchFormat. Full f -> s2cBranch (joinFull f ds)
592+ S.BranchFormat. Diff ref' d' -> doDiff ref' (d' : ds)
593+ where
594+ joinFull :: S. Branch -> [S.Branch. Diff ] -> S. Branch
595+ joinFull f [] = f
596+ joinFull
597+ (S.Branch.Full. Branch tms tps patches children)
598+ (S.Branch. Diff tms' tps' patches' children' : ds) = joinFull f' ds
599+ where
600+ f' =
601+ S.Branch.Full. Branch
602+ (mergeDefns tms tms')
603+ (mergeDefns tps tps')
604+ (mergePatches patches patches')
605+ (mergeChildren children children')
606+ mergeChildren ::
607+ Map S.Branch.Full. NameSegment Db. BranchObjectId ->
608+ Map S.BranchDiff. NameSegment S.BranchDiff. ChildOp ->
609+ Map S.Branch.Full. NameSegment Db. BranchObjectId
610+ mergeChildren =
611+ Map. merge
612+ Map. preserveMissing
613+ (Map. mapMissing fromChildOp)
614+ (Map. zipWithMaybeMatched mergeChildOp)
615+ mergeChildOp ::
616+ S.Branch. NameSegment ->
617+ Db. BranchObjectId ->
618+ S.BranchDiff. ChildOp ->
619+ Maybe Db. BranchObjectId
620+ mergeChildOp =
621+ const . const \ case
622+ S.BranchDiff. ChildAddReplace id -> Just id
623+ S.BranchDiff. ChildRemove -> Nothing
624+ fromChildOp :: S.Branch. NameSegment -> S.BranchDiff. ChildOp -> Db. BranchObjectId
625+ fromChildOp = const \ case
626+ S.BranchDiff. ChildAddReplace id -> id
627+ S.BranchDiff. ChildRemove -> error " diff tries to remove a nonexistent child"
628+ mergePatches ::
629+ Map S.Branch.Full. NameSegment Db. PatchObjectId ->
630+ Map S.BranchDiff. NameSegment S.BranchDiff. PatchOp ->
631+ Map S.Branch.Full. NameSegment Db. PatchObjectId
632+ mergePatches =
633+ Map. merge Map. preserveMissing (Map. mapMissing fromPatchOp) (Map. zipWithMaybeMatched mergePatchOp)
634+ fromPatchOp :: S.Branch. NameSegment -> S.BranchDiff. PatchOp -> Db. PatchObjectId
635+ fromPatchOp = const \ case
636+ S.BranchDiff. PatchAddReplace id -> id
637+ S.BranchDiff. PatchRemove -> error " diff tries to remove a nonexistent child"
638+ mergePatchOp :: S.Branch. NameSegment -> Db. PatchObjectId -> S.BranchDiff. PatchOp -> Maybe Db. PatchObjectId
639+ mergePatchOp =
640+ const . const \ case
641+ S.BranchDiff. PatchAddReplace id -> Just id
642+ S.BranchDiff. PatchRemove -> Nothing
643+ mergeDefns ::
644+ Ord r =>
645+ Map S.BranchDiff. NameSegment (Map r S.MetadataSet. MetadataSetFormat ) ->
646+ Map S.BranchDiff. NameSegment (Map r S.BranchDiff. DefinitionOp ) ->
647+ Map S.BranchDiff. NameSegment (Map r S.MetadataSet. MetadataSetFormat )
648+ mergeDefns =
649+ Map. merge
650+ Map. preserveMissing
651+ (Map. mapMissing (const (fmap fromDefnOp)))
652+ (Map. zipWithMatched (const mergeDefnOp))
653+ fromDefnOp :: S.BranchDiff. DefinitionOp -> S.MetadataSet. MetadataSetFormat
654+ fromDefnOp = \ case
655+ S.Branch.Diff. AddDefWithMetadata md -> S.MetadataSet. Inline md
656+ S.Branch.Diff. RemoveDef -> error " diff tries to remove a nonexistent definition"
657+ S.Branch.Diff. AlterDefMetadata _md -> error " diff tries to change metadata for a nonexistent definition"
658+ mergeDefnOp ::
659+ Ord r =>
660+ Map r S.MetadataSet. MetadataSetFormat ->
661+ Map r S.BranchDiff. DefinitionOp ->
662+ Map r S.MetadataSet. MetadataSetFormat
663+ mergeDefnOp =
664+ Map. merge
665+ Map. preserveMissing
666+ (Map. mapMissing (const fromDefnOp))
667+ (Map. zipWithMaybeMatched (const mergeDefnOp'))
668+ mergeDefnOp' ::
669+ S.MetadataSet. MetadataSetFormat ->
670+ S.BranchDiff. DefinitionOp ->
671+ Maybe S.MetadataSet. MetadataSetFormat
672+ mergeDefnOp' (S.MetadataSet. Inline md) = \ case
673+ S.Branch.Diff. AddDefWithMetadata _md ->
674+ error " diff tries to create a child that already exists"
675+ S.Branch.Diff. RemoveDef -> Nothing
676+ S.Branch.Diff. AlterDefMetadata md' ->
677+ let (Set. fromList -> adds, Set. fromList -> removes) = S.BranchDiff. addsRemoves md'
678+ in Just . S.MetadataSet. Inline $ (Set. union adds $ Set. difference md removes)
464679
465680branchHashesByPrefix :: EDB m => ShortBranchHash -> m (Set BranchHash )
466681branchHashesByPrefix (ShortBranchHash b32prefix) = do
0 commit comments