packages feed

family-tree 0.4.1.1 → 0.5

raw patch · 3 files changed

+138/−130 lines, 3 filesdep +hashabledep +tablesPVP ok

version bump matches the API change (PVP)

Dependencies added: hashable, tables

API changes (from Hackage documentation)

- Data.FamilyTree: FamilyID :: Int -> FamilyID
- Data.FamilyTree: PersonID :: Int -> PersonID
- Data.FamilyTree: getFamilyID :: FamilyID -> Int
- Data.FamilyTree: getPersonID :: PersonID -> Int
- Data.FamilyTree: instance Eq FamilyID
- Data.FamilyTree: instance Eq PersonID
- Data.FamilyTree: instance Ord FamilyID
- Data.FamilyTree: instance Ord PersonID
- Data.FamilyTree: instance Read FamilyID
- Data.FamilyTree: instance Read PersonID
- Data.FamilyTree: instance Show FamilyID
- Data.FamilyTree: instance Show PersonID
- Data.FamilyTree: instance Wrapped Int Int FamilyID FamilyID
- Data.FamilyTree: instance Wrapped Int Int PersonID PersonID
- Data.FamilyTree: newtype FamilyID
- Data.FamilyTree: newtype PersonID
+ Data.FamilyTree: _familyId :: Family -> Int
+ Data.FamilyTree: _personId :: Person -> Int
+ Data.FamilyTree: instance Constructor C1_0Family
+ Data.FamilyTree: instance Constructor C1_0FamilyTree
+ Data.FamilyTree: instance Constructor C1_0Location
+ Data.FamilyTree: instance Constructor C1_0Person
+ Data.FamilyTree: instance Constructor C1_0Relationship
+ Data.FamilyTree: instance Constructor C1_1Location
+ Data.FamilyTree: instance Constructor C1_1Relationship
+ Data.FamilyTree: instance Datatype D1Family
+ Data.FamilyTree: instance Datatype D1FamilyTree
+ Data.FamilyTree: instance Datatype D1Location
+ Data.FamilyTree: instance Datatype D1Person
+ Data.FamilyTree: instance Datatype D1Relationship
+ Data.FamilyTree: instance Generic Family
+ Data.FamilyTree: instance Generic FamilyTree
+ Data.FamilyTree: instance Generic Location
+ Data.FamilyTree: instance Generic Person
+ Data.FamilyTree: instance Generic Relationship
+ Data.FamilyTree: instance Hashable Location
+ Data.FamilyTree: instance Hashable Relationship
+ Data.FamilyTree: instance Selector S1_0_0Family
+ Data.FamilyTree: instance Selector S1_0_0FamilyTree
+ Data.FamilyTree: instance Selector S1_0_0Person
+ Data.FamilyTree: instance Selector S1_0_1Family
+ Data.FamilyTree: instance Selector S1_0_1FamilyTree
+ Data.FamilyTree: instance Selector S1_0_1Person
+ Data.FamilyTree: instance Selector S1_0_2Family
+ Data.FamilyTree: instance Selector S1_0_2FamilyTree
+ Data.FamilyTree: instance Selector S1_0_2Person
+ Data.FamilyTree: instance Selector S1_0_3Family
+ Data.FamilyTree: instance Selector S1_0_3Person
+ Data.FamilyTree: instance Selector S1_0_4Family
+ Data.FamilyTree: instance Selector S1_0_4Person
+ Data.FamilyTree: instance Selector S1_0_5Family
+ Data.FamilyTree: instance Selector S1_0_5Person
+ Data.FamilyTree: instance Selector S1_0_6Family
+ Data.FamilyTree: instance Selector S1_0_6Person
+ Data.FamilyTree: instance Tabular Family
+ Data.FamilyTree: instance Tabular Person
- Data.FamilyTree: Family :: Maybe PersonID -> Maybe PersonID -> Maybe Relationship -> Maybe PartialDate -> Maybe PartialDate -> IntSet -> Family
+ Data.FamilyTree: Family :: Int -> Maybe Int -> Maybe Int -> Maybe Relationship -> Maybe PartialDate -> Maybe PartialDate -> IntSet -> Family
- Data.FamilyTree: FamilyTree :: Text -> IntMap Person -> IntMap Family -> FamilyTree
+ Data.FamilyTree: FamilyTree :: Text -> Table Person -> Table Family -> FamilyTree
- Data.FamilyTree: Person :: Maybe Text -> Maybe PartialDate -> Maybe Location -> Maybe PartialDate -> Maybe Location -> HashMap Text Text -> Person
+ Data.FamilyTree: Person :: Int -> Maybe Text -> Maybe PartialDate -> Maybe Location -> Maybe PartialDate -> Maybe Location -> HashMap Text Text -> Person
- Data.FamilyTree: _families :: FamilyTree -> IntMap Family
+ Data.FamilyTree: _families :: FamilyTree -> Table Family
- Data.FamilyTree: _head1 :: Family -> Maybe PersonID
+ Data.FamilyTree: _head1 :: Family -> Maybe Int
- Data.FamilyTree: _head2 :: Family -> Maybe PersonID
+ Data.FamilyTree: _head2 :: Family -> Maybe Int
- Data.FamilyTree: _people :: FamilyTree -> IntMap Person
+ Data.FamilyTree: _people :: FamilyTree -> Table Person
- Data.FamilyTree: accessFT :: FamilyTreePart part => ID part -> IndexedTraversal' (ID part) FamilyTree part
+ Data.FamilyTree: accessFT :: FamilyTreePart part => Int -> IndexedTraversal' Int FamilyTree part
- Data.FamilyTree: addFamily :: FamilyTree -> (FamilyID, FamilyTree)
+ Data.FamilyTree: addFamily :: FamilyTree -> (Int, FamilyTree)
- Data.FamilyTree: addPerson :: FamilyTree -> (PersonID, FamilyTree)
+ Data.FamilyTree: addPerson :: FamilyTree -> (Int, FamilyTree)
- Data.FamilyTree: class FamilyTreePart part where type family ID part
+ Data.FamilyTree: class FamilyTreePart part
- Data.FamilyTree: deleteFamily :: FamilyID -> FamilyTree -> FamilyTree
+ Data.FamilyTree: deleteFamily :: Int -> FamilyTree -> FamilyTree
- Data.FamilyTree: deletePerson :: PersonID -> FamilyTree -> FamilyTree
+ Data.FamilyTree: deletePerson :: Int -> FamilyTree -> FamilyTree
- Data.FamilyTree: families :: Lens' FamilyTree (IntMap Family)
+ Data.FamilyTree: families :: Lens' FamilyTree (Table Family)
- Data.FamilyTree: head1 :: Lens' Family (Maybe PersonID)
+ Data.FamilyTree: head1 :: Lens' Family (Maybe Int)
- Data.FamilyTree: head2 :: Lens' Family (Maybe PersonID)
+ Data.FamilyTree: head2 :: Lens' Family (Maybe Int)
- Data.FamilyTree: people :: Lens' FamilyTree (IntMap Person)
+ Data.FamilyTree: people :: Lens' FamilyTree (Table Person)

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012, Nathan "Taneb" van Doorn+Copyright (c) 2013, Nathan "Taneb" van Doorn  All rights reserved. 
family-tree.cabal view
@@ -1,63 +1,21 @@--- Initial family-tree.cabal generated by cabal init.  For further --- documentation, see http://haskell.org/cabal/users-guide/---- The name of the package. name:                family-tree---- The package version.  See the Haskell package versioning policy (PVP) --- for standards guiding when and how versions should be incremented.--- http://www.haskell.org/haskellwiki/Package_versioning_policy--- PVP summary:      +-+------- breaking API changes---                   | | +----- non-breaking API additions---                   | | | +--- code changes with no API change-version:             0.4.1.1-+version:             0.5 package-url:         https://github.com/Taneb/family-tree---- A short (one-line) description of the package. synopsis:            A family tree library for the Haskell programming language.---- A longer description of the package. description:         A family tree library for the Haskell programming language.                                            Uses "Control.Lens" for modification and "Data.Binary" for                      serialization.---- URL for the project homepage or repository. homepage:            https://github.com/Taneb/family-tree---- The license under which the package is released. license:             BSD3---- The file containing the license text. license-file:        LICENSE---- The package author(s). author:              Nathan "Taneb" van Doorn---- An email address to which users can send suggestions, bug reports, and --- patches. maintainer:          nvd1234@gmail.com---- A copyright notice.--- copyright:           - category:            Data, Genealogy- build-type:          Simple---- Constraint on the version of Cabal needed to build this package. cabal-version:       >=1.8-- library-  -- Modules exported by the library.   exposed-modules:     Data.FamilyTree-  -  -- Modules included in this library but not exported.-  -- other-modules:       -  -  -- Other library packages from which modules are imported.   build-depends:       base >= 4.3 && < 5,                        lens >= 3.8 && < 3.10,                        binary < 0.7,@@ -65,9 +23,9 @@                        containers >=0.4.2 && < 0.6,                        text ==0.11.*,                        time < 1.5,-                       intervals < 0.3-  -  -- Directories containing source files.+                       intervals < 0.3,+                       tables ==0.3.*,+                       hashable >= 1.1.1.0 && < 1.3   hs-source-dirs:      src  source-repository head
src/Data/FamilyTree.hs view
@@ -1,5 +1,5 @@+{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-}@@ -16,8 +16,6 @@ "Control.Lens"  It is reccomended to use "Data.Binary" to do saving and loading.-- -} module Data.FamilyTree  (@@ -37,15 +35,10 @@  relationFrom,  relationTo,  relationship,-    FamilyTree(..),  treeName,  people,  families,-  -- ** ID types- -- $ids- PersonID(..),- FamilyID(..),  -- ** Other types  PartialDate,  Location(..),@@ -66,52 +59,36 @@  partialDateFromDay ) where -import Control.Applicative (Applicative(..), (<$>), Alternative(..))+import Control.Applicative (Applicative(..), (<$>), Alternative((<|>))) import Control.Lens hiding (children) -import Data.Binary (Word8, Binary(..), getWord8)+import Data.Binary (Binary(..), putWord8, getWord8) import Data.Function (on)+import Data.Hashable (Hashable(..)) import Data.HashMap.Strict (HashMap) import qualified Data.HashMap.Strict as HM-import Data.Maybe (listToMaybe) import Data.Monoid (Monoid(..), First(..))-import Data.IntMap (IntMap)-import qualified Data.IntMap as IM import Data.IntSet (IntSet) import qualified Data.IntSet as IS---import Data.Table+import Data.Table import Data.String import Data.Text (Text)---import qualified Data.Text as T import Data.Text.Encoding (encodeUtf8, decodeUtf8) import Data.Time (Day(..), fromGregorian, gregorianMonthLength) +import GHC.Generics (Generic)+ import Numeric.Interval (Interval) import qualified Numeric.Interval as I --- $ids--- The various ID types represent an identifier for a person, family, or event. --- While the constructors are exported, it is probably better to use the--- various 'Traversal's for manipulation, as they echo the changes around the--- tree automatically.-newtype PersonID = PersonID {getPersonID :: Int} deriving (Eq, Ord, Show, Read)--instance Wrapped Int Int PersonID PersonID where-  wrapped = iso PersonID getPersonID--newtype FamilyID = FamilyID {getFamilyID :: Int} deriving (Eq, Ord, Show, Read)--instance Wrapped Int Int FamilyID FamilyID where-  wrapped = iso FamilyID getFamilyID- -- | The Location type. Either a coordinate or a placename.  -data Location = Coord Double Double | PlaceName Text deriving (Eq, Show)+data Location = Coord Double Double | PlaceName Text deriving (Eq, Show, Generic)  instance IsString Location where   fromString = PlaceName . fromString    -- | The Relationship type. Marriage is the default for similarity to GEDCOM.-data Relationship = Marriage | Other Text deriving (Eq, Show)+data Relationship = Marriage | Other Text deriving (Eq, Show, Generic)  type PartialDate = Interval Day @@ -129,40 +106,114 @@ -- non-existent, for intance a death date for someone still alive) is a -- convention used throughout this library. data Person = Person-  {_name :: Maybe Text+  {_personId :: Int+  ,_name :: Maybe Text   ,_birthdate :: Maybe PartialDate   ,_birthplace :: Maybe Location   ,_deathdate :: Maybe PartialDate   ,_deathplace :: Maybe Location   ,_attributes :: HashMap Text Text-  } deriving (Eq, Show)+  } deriving (Eq, Show, Generic)               makeLenses ''Person +instance Tabular Person where+  type PKT Person = Int+  data Tab Person i = PersonTab (i Primary Int) (i SupplementalHash (Maybe Text)) (i Supplemental (Maybe PartialDate))+                      (i SupplementalHash (Maybe Location)) (i Supplemental (Maybe PartialDate)) +                      (i SupplementalHash (Maybe Location))+  data Key k Person t where+    PersonID :: Key Primary Person Int+    Name :: Key SupplementalHash Person (Maybe Text)+    BirthDate :: Key Supplemental Person (Maybe PartialDate)+    BirthPlace :: Key SupplementalHash Person (Maybe Location)+    DeathDate :: Key Supplemental Person (Maybe PartialDate)+    DeathPlace :: Key SupplementalHash Person (Maybe Location)+  fetch PersonID = _personId+  fetch Name = _name+  fetch BirthDate = _birthdate+  fetch BirthPlace = _birthplace+  fetch DeathDate = _deathdate+  fetch DeathPlace = _deathplace+  primary = PersonID+  primarily PersonID r = r+  mkTab f = PersonTab <$> f PersonID <*> f Name <*> f BirthDate <*> f BirthPlace+            <*> f DeathDate <*> f DeathPlace  +  ixTab (PersonTab i n bd bp dd dp) k = case k of+    PersonID -> i+    Name -> n+    BirthDate -> bd+    BirthPlace -> bp+    DeathDate -> dd+    DeathPlace -> dp+  forTab (PersonTab i n bd bp dd dp) f =+    PersonTab <$> f PersonID i <*> f Name n <*> f BirthDate bd <*> f BirthPlace bp+    <*> f DeathDate dd <*> f DeathPlace dp+  autoTab = autoIncrement personId+ -- | The basic type for a family. Which person is head1 and which is head2 is -- arbitrary, but try to use a consistent rule data Family = Family-  {_head1 :: Maybe PersonID-  ,_head2 :: Maybe PersonID+  {_familyId :: Int+  ,_head1 :: Maybe Int+  ,_head2 :: Maybe Int   ,_relationship :: Maybe Relationship   ,_relationFrom :: Maybe PartialDate   ,_relationTo :: Maybe PartialDate   ,_children :: IntSet-  } deriving (Eq, Show)+  } deriving (Eq, Show, Generic)    makeLenses ''Family +instance Tabular Family where+  type PKT Family = Int+  data Tab Family i = FamilyTab (i Primary Int) (i Supplemental (Maybe Int)) (i Supplemental (Maybe Int))+                      (i SupplementalHash (Maybe Relationship)) (i Supplemental (Maybe PartialDate))+                      (i Supplemental (Maybe PartialDate)) (i InvertedInt (IntSet))+  data Key k Family t where+    FamilyID :: Key Primary Family Int+    Head1 :: Key Supplemental Family (Maybe Int)+    Head2 :: Key Supplemental Family (Maybe Int)+    Relationship :: Key SupplementalHash Family (Maybe Relationship)+    RelationFrom :: Key Supplemental Family (Maybe PartialDate)+    RelationTo :: Key Supplemental Family (Maybe PartialDate)+    Children :: Key InvertedInt Family IntSet+  fetch FamilyID = _familyId+  fetch Head1 = _head1+  fetch Head2 = _head2+  fetch Relationship = _relationship+  fetch RelationFrom = _relationFrom+  fetch RelationTo = _relationTo+  fetch Children = _children+  primary = FamilyID+  primarily FamilyID r = r+  mkTab f = FamilyTab <$> f FamilyID <*> f Head1 <*> f Head2 <*> f Relationship+            <*> f RelationFrom <*> f RelationTo <*> f Children+  ixTab (FamilyTab i h1 h2 r rf rt c) k = case k of+    FamilyID -> i+    Head1 -> h1+    Head2 -> h2+    Relationship -> r+    RelationFrom -> rf+    RelationTo -> rt+    Children -> c+  forTab (FamilyTab i h1 h2 r rf rt c) f =+    FamilyTab <$> f FamilyID i <*> f Head1 h1 <*> f Head2 h2 <*> f Relationship r+    <*> f RelationFrom rf <*> f RelationTo rt <*> f Children c+  autoTab = autoIncrement familyId+ -- | The core structure of a family tree. data FamilyTree = FamilyTree   {_treeName :: Text-  ,_people :: IntMap Person-  ,_families :: IntMap Family-  } deriving (Eq, Show)+  ,_people :: Table Person+  ,_families :: Table Family+  } deriving (Eq, Show, Generic)    makeLenses ''FamilyTree  instance Monoid Person where   mempty = Person {+    _personId = 0,     _name = Nothing,     _birthdate = Nothing,     _birthplace = Nothing,@@ -171,6 +222,7 @@     _attributes = HM.empty     }   p1 `mappend` p2 = Person {+    _personId = _personId p1,     _name = ((<|>) `on` _name) p1 p2,     _birthdate = ((<|>) `on` _birthdate) p1 p2,     _birthplace = ((<|>) `on` _birthplace) p1 p2,@@ -181,6 +233,7 @@  instance Monoid Family where   mempty = Family {+    _familyId = 0,     _head1 = Nothing,     _head2 = Nothing,     _relationship = Nothing,@@ -189,6 +242,7 @@     _children = IS.empty     }   f1 `mappend` f2 = Family {+    _familyId = _familyId f1,     _head1 = getFirst $ (mappend `on` First . _head1) f1 f2,     _head2 = getFirst $ (mappend `on` First . _head2) f1 f2,     _relationship = getFirst $ (mappend `on` First . _relationship) f1 f2,@@ -199,11 +253,11 @@  instance Binary Location where   put (Coord x y) = do-    put (0 :: Word8)+    putWord8 0     put x     put y   put (PlaceName t) = do-    put (1 :: Word8)+    putWord8 1     put (encodeUtf8 t)   get = do     tag <- getWord8@@ -214,19 +268,24 @@         return $ Coord x y       _ -> PlaceName . decodeUtf8 <$> get +instance Hashable Location+   instance Binary Relationship where   put (Other t) = do-    put (0 :: Word8)+    putWord8 0     put (encodeUtf8 t)-  put Marriage = put (1 :: Word8)+  put Marriage = putWord8 1   get = do     tag <- getWord8     case tag of       0 -> Other . decodeUtf8 <$> get       _ -> return Marriage +instance Hashable Relationship+ instance Binary Person where   put person = do+    put (_personId person)     put (encodeUtf8 <$> _name person)     put (toModifiedJulianDay . I.inf <$> _birthdate person)     put (toModifiedJulianDay . I.sup <$> _birthdate person)@@ -236,6 +295,7 @@     put (_deathplace person)     put (map (both %~ encodeUtf8) . HM.toList $ _attributes person)   get = do+    i <- get     n <- get     bdi <- get     bds <- get@@ -245,7 +305,8 @@     dp <- get     a <- get     return Person-      {_name = fmap decodeUtf8 n+      {_personId = i+      ,_name = fmap decodeUtf8 n       ,_birthdate = I.I <$> fmap ModifiedJulianDay bdi <*>         fmap ModifiedJulianDay bds       ,_birthplace = bp@@ -257,8 +318,9 @@  instance Binary Family where   put fam = do-    put $ getPersonID <$> _head1 fam-    put $ getPersonID <$> _head2 fam+    put $ _familyId fam+    put $ _head1 fam+    put $ _head2 fam     put $ _relationship fam     put $ toModifiedJulianDay . I.inf <$> _relationFrom fam     put $ toModifiedJulianDay . I.sup <$> _relationFrom fam@@ -266,6 +328,7 @@     put $ toModifiedJulianDay . I.sup <$> _relationTo fam     put $ _children fam   get = do+    f <- get     h1 <- get     h2 <- get     r <- get@@ -275,8 +338,9 @@     rts <- get     c <- get     return Family-      {_head1 = PersonID <$> h1-      ,_head2 = PersonID <$> h2+      {_familyId = f+      ,_head1 = h1+      ,_head2 = h2       ,_relationship = r       ,_relationFrom = I.I <$> fmap ModifiedJulianDay rfi <*> fmap ModifiedJulianDay rfs       ,_relationTo = I.I <$> fmap ModifiedJulianDay rti <*> fmap ModifiedJulianDay rts@@ -299,25 +363,22 @@       }  class FamilyTreePart part where-  type ID part-  -- | 'accessFT' is a 'Traversal' to the part of the family tree (either a 'Person' or a 'Family') with the given 'ID'-  accessFT :: ID part -> IndexedTraversal' (ID part) FamilyTree part+  -- | 'accessFT' is a 'Traversal' to the part of the family tree (either a 'Person' or a 'Family')+  accessFT :: Int -> IndexedTraversal' Int FamilyTree part  instance FamilyTreePart Person where-  type ID Person = PersonID-  accessFT (PersonID n) f familyTree = case familyTree ^. people . at n of+  accessFT n f familyTree = case familyTree ^. people . at n of     Nothing -> pure familyTree     Just oldPerson ->-      let newPerson_ = indexed f (PersonID n) oldPerson+      let newPerson_ = indexed f n oldPerson       in alterPerson <$> newPerson_     where       alterPerson newPerson = people . ix n .~ newPerson $ familyTree  instance FamilyTreePart Family where-  type ID Family = FamilyID-  accessFT (FamilyID n) f familyTree = case familyTree ^. families . at n of+  accessFT n f familyTree = case familyTree ^. families . at n of     Nothing -> pure familyTree-    Just oldFamily -> let newFamily_ = indexed f (FamilyID n) oldFamily+    Just oldFamily -> let newFamily_ = indexed f n oldFamily                       in alterFamily <$> newFamily_     where       alterFamily newFamily =@@ -325,46 +386,35 @@  -- | Adds a person with minimal information, returning the updated family tree -- and the ID of the new person.  -addPerson :: FamilyTree -> (PersonID, FamilyTree)-addPerson familyTree =-  let n = maybe 0 fst $-          listToMaybe $-          dropWhile (uncurry (==)) $-          zip [1 ..] $ IM.keys $ _people familyTree-  in (PersonID n, people . at n ?~ mempty $ familyTree)+addPerson :: FamilyTree -> (Int, FamilyTree)+addPerson = people %%~ (_1 %~ _personId) . insert' mempty  -- | Adds a family with minimal information, returning the updated family tree -- and the ID of the new family.  -addFamily :: FamilyTree -> (FamilyID, FamilyTree)-addFamily familyTree =-  let n = maybe 0 fst $-          listToMaybe $-          dropWhile (uncurry (==)) $-          zip [1 ..] $ IM.keys $ _families familyTree-  in (FamilyID n, families . at n ?~ mempty $ familyTree)+addFamily :: FamilyTree -> (Int, FamilyTree)+addFamily = families %%~ (_1 %~ _familyId) . insert' mempty  -- | Deletes a person from the family tree, removing all references to them.  -deletePerson :: PersonID -> FamilyTree -> FamilyTree-deletePerson (PersonID n) familyTree =+deletePerson :: Int -> FamilyTree -> FamilyTree+deletePerson n familyTree =   familyTree &   people . at n .~ Nothing &-  families %~ IM.map (+  families . each %~      \fam -> fam &-            head1 %~ (id & ix (Just $ PersonID n) .~ Nothing) &-            head2 %~ (id & ix (Just $ PersonID n) .~ Nothing) &+            head1 %~ set (ix $ Just n) Nothing id & +            head2 %~ set (ix $ Just n) Nothing id &             children . contains n .~ False-            )+              -- | Deletes a family from the family tree, removing all references to it.    -deleteFamily :: FamilyID -> FamilyTree -> FamilyTree-deleteFamily (FamilyID n) = families . at n .~ Nothing+deleteFamily :: Int -> FamilyTree -> FamilyTree+deleteFamily n = families . at n .~ Nothing  -- | Creates a new tree with a given name.        newTree :: Text -> FamilyTree newTree n = FamilyTree   {_treeName = n-  ,_people = IM.empty-  ,_families = IM.empty+  ,_people = empty+  ,_families = empty   }-