diff --git a/Text/VCard/Query.hs b/Text/VCard/Query.hs
new file mode 100644
--- /dev/null
+++ b/Text/VCard/Query.hs
@@ -0,0 +1,51 @@
+-- |
+-- Copyright   : (c) 2008 Mathieu Boespflug
+-- License     : LGPL
+-- Maintainer  : mboes@tweag.net
+-- Stability   : experimental
+-- Portability : portable
+
+module Text.VCard.Query where
+
+import Text.VCard.Types
+import qualified Codec.MIME.ContentType.Text.Directory as D
+import qualified Data.Map as Map
+import Data.Maybe (fromJust)
+import qualified Data.ByteString.Lazy.Char8.Caseless as I
+
+
+lookup :: I.ByteString -> VCard -> Maybe [VCardValue]
+lookup typ vcard =
+    fmap (Prelude.map D.prop_value) $ Map.lookup typ (vcard_properties vcard)
+
+-- | Unsafe variant that assumes given type name maps to exactly one value in the vCard.
+lookup' :: I.ByteString -> VCard -> VCardValue
+lookup' typ vcard =
+     D.prop_value $ head $ fromJust $ Map.lookup typ (vcard_properties vcard)
+
+insert :: VProperty -> VCard -> VCard
+insert p vcard@(VCard {vcard_properties = attrs}) =
+    vcard{ vcard_properties = Map.insertWith merge (D.type_name (D.prop_type p)) [p] attrs }
+    where merge [p] ps = p:ps
+
+filterWithProperty :: (VProperty -> Bool) -> [VCard] -> [VCard]
+filterWithProperty f =
+    Prelude.filter (not . Map.null . (Map.filter (not . null . Prelude.filter f) . vcard_properties))
+
+filterWithType :: (D.Type -> VCardValue -> Bool) -> [VCard] -> [VCard]
+filterWithType f = filterWithProperty (\prop -> f (D.prop_type prop) (D.prop_value prop))
+
+filter :: (VCardValue -> Bool) -> [VCard] -> [VCard]
+filter f = filterWithProperty (\prop -> f (D.prop_value prop))
+
+mapWithProperty :: (VProperty -> VCardValue) -> [VCard] -> [VCard]
+mapWithProperty f = Prelude.map updateVCard
+    where updateProp prop = prop { D.prop_value = (f prop) }
+          updateVCard vcard =
+              vcard { vcard_properties = Map.map (Prelude.map updateProp) (vcard_properties vcard) }
+
+mapWithType :: (D.Type -> VCardValue -> VCardValue) -> [VCard] -> [VCard]
+mapWithType f = mapWithProperty (\prop -> f (D.prop_type prop) (D.prop_value prop))
+
+map :: (VCardValue -> VCardValue) -> [VCard] -> [VCard]
+map f = mapWithProperty (\prop -> f (D.prop_value prop))
diff --git a/Text/VCard/Types.hs b/Text/VCard/Types.hs
new file mode 100644
--- /dev/null
+++ b/Text/VCard/Types.hs
@@ -0,0 +1,42 @@
+-- |
+-- Copyright   : (c) 2008 Mathieu Boespflug
+-- License     : LGPL
+-- Maintainer  : mboes@tweag.net
+-- Stability   : experimental
+-- Portability : non-portable
+
+module Text.VCard.Types
+    ( Version(..), ExtraValue(..), VCard(..)
+    , VCardValue, VProperty, SourceName ) where
+
+import qualified Data.Map as Map
+import qualified Codec.MIME.ContentType.Text.Directory as D
+import qualified Data.ByteString.Lazy.Char8 as B
+import qualified Data.ByteString.Lazy.Char8.Caseless as I
+
+
+data Version = Version
+    { version_major :: Int
+    , version_minor :: Int }
+               deriving Show
+
+data ExtraValue = Struct [[B.ByteString]]
+                | Binary B.ByteString
+                | PhoneNumber B.ByteString
+                | UTCOffset { utcOffset_sign :: Char
+                            , utcOffset_hours :: Int
+                            -- ^ Valid range: 0-23
+                            , utcOffset_minutes :: Int
+                            -- ^ Valid range: 0-25
+                            }
+                | SubVCard VCard
+                  deriving Show
+
+type VCardValue = D.Value ExtraValue
+type VProperty = D.Property ExtraValue
+type SourceName = String
+
+data VCard = VCard
+    { vcard_version :: Version
+    , vcard_properties :: Map.Map I.ByteString [VProperty] }
+             deriving Show
diff --git a/vcard.cabal b/vcard.cabal
--- a/vcard.cabal
+++ b/vcard.cabal
@@ -1,5 +1,5 @@
 name:           vcard
-version:        0.1.1
+version:        0.1.2
 author:         Mathieu Boespflug
 maintainer:     Mathieu Boespflug <mboes@tweag.net>
 homepage:       http://code.haskell.org/~mboes/vcard.git
@@ -20,5 +20,7 @@
     build-depends:   base >= 3, containers, bytestring >= 0.9,
                      mime-directory >= 0.1
     exposed-modules: Text.VCard
-                     Text.VCard.Format.Directory
+                     Text.VCard.Types
+                     Text.VCard.Query
                      Text.VCard.Selectors
+                     Text.VCard.Format.Directory
