mmzk-typeid 0.5.0.1 → 0.5.0.2
raw patch · 22 files changed
+216/−209 lines, 22 files
Files
- CHANGELOG.md +9/−1
- README.md +1/−1
- mmzk-typeid.cabal +11/−1
- src/Data/KindID.hs +5/−6
- src/Data/KindID/Class.hs +5/−5
- src/Data/KindID/Internal.hs +5/−4
- src/Data/KindID/Unsafe.hs +4/−5
- src/Data/KindID/V1.hs +0/−2
- src/Data/KindID/V1/Unsafe.hs +0/−2
- src/Data/KindID/V4.hs +0/−2
- src/Data/KindID/V4/Unsafe.hs +0/−2
- src/Data/KindID/V5.hs +0/−2
- src/Data/KindID/V5/Unsafe.hs +0/−2
- src/Data/KindID/V7/Unsafe.hs +4/−5
- src/Data/TypeID/Class.hs +2/−2
- src/Data/TypeID/Internal.hs +8/−6
- src/Data/TypeID/Unsafe.hs +3/−4
- src/Data/TypeID/V1/Unsafe.hs +0/−1
- src/Data/TypeID/V4/Unsafe.hs +2/−2
- src/Data/TypeID/V5/Unsafe.hs +0/−1
- src/Data/TypeID/V7/Unsafe.hs +5/−4
- test/Spec.hs +152/−149
CHANGELOG.md view
@@ -1,7 +1,15 @@ # Revision history for mmzk-typeid -## 0.5.0.1 --2023-9-18+## 0.5.0.2 -- 2024-3-10++* Add `Typeable` and `Data` instances for `TypeID` and `KindID`.+ * Kindly contributed by @shinzui.++* Fix all warnings.+++## 0.5.0.1 -- 2023-9-18 * Fix bad links in the documentation.
README.md view
@@ -22,7 +22,7 @@ 1. Generating TypeIDs in a batch. They are guaranteed to have the same timestamp (up to the first 32768 ids) and of ascending order; 2. Encoding the prefix in the [type level](https://hackage.haskell.org/package/mmzk-typeid/docs/Data-KindID.html), so that if you accidentally pass in a wrong prefix, the code won't compile, avoiding the need for runtime checks.-3. Support TypeID with other UUID versions. Currently v7 (default) and v4 are supported.+3. Support TypeID with other UUID versions. Currently v7 (default), v1, v4, and v5 are supported. ## Quick start
mmzk-typeid.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: mmzk-typeid-version: 0.5.0.1+version: 0.5.0.2 synopsis: A TypeID implementation for Haskell description:@@ -79,6 +79,9 @@ BlockArguments ConstraintKinds DataKinds+ DeriveAnyClass+ DeriveDataTypeable+ DeriveGeneric FlexibleContexts FlexibleInstances InstanceSigs@@ -103,6 +106,8 @@ time >=1.11 && <1.13, uuid ^>=1.3, uuid-types ^>=1.0,+ ghc-options:+ -Wall hs-source-dirs: src default-language: Haskell2010 @@ -142,6 +147,9 @@ BlockArguments ConstraintKinds DataKinds+ DeriveAnyClass+ DeriveDataTypeable+ DeriveGeneric FlexibleContexts FlexibleInstances InstanceSigs@@ -168,6 +176,8 @@ time, uuid, uuid-types,+ ghc-options:+ -Wall hs-source-dirs: src test
src/Data/KindID.hs view
@@ -7,10 +7,11 @@ -- Similar to "Data.TypeID", but the type is statically determined in the type -- level. ----- When using 'TypeID', if we want to check if the type matches, we usually need--- to get the prefix of the 'TypeID' and compare it with the desired prefix at--- runtime. However, with Haskell's type system, we can do this at compile time--- instead. We call this TypeID with compile-time prefix a 'KindID'.+-- When using 'Data.TypeID.V7.TypeID', if we want to check if the type matches,+-- we usually need to get the prefix of the 'Data.TypeID.V7.TypeID' and compare+-- it with the desired prefix at runtime. However, with Haskell's type system,+-- we can do this at compile time instead. We call this TypeID with compile-time+-- prefix a 'KindID'. -- -- Of course, that would require the desired prefix to be known at compile time. -- This is actually quite common, especially when we are using one prefix for@@ -87,5 +88,3 @@ import Data.KindID.Internal (KindID') import Data.KindID.V7-import Data.TypeID.Class-import Data.TypeID.V7 (TypeID)
src/Data/KindID/Class.hs view
@@ -15,11 +15,11 @@ ValidPrefix , ToPrefix(..) -- * Helpers- , LengthSymbol(..)- , IsLowerSymbol(..)- , IsLowerChar(..)- , LSUH(..)- , ILSUH(..)+ , LengthSymbol+ , IsLowerSymbol+ , IsLowerChar+ , LSUH+ , ILSUH ) where import Data.Type.Bool
src/Data/KindID/Internal.hs view
@@ -13,11 +13,13 @@ import Data.Aeson.Types hiding (String) import Data.Binary import Data.ByteString.Lazy (ByteString)+import Data.Data (Data) import Data.Hashable import Data.Proxy import Data.KindID.Class import Data.Text (Text) import qualified Data.Text as T+import Data.Typeable (Typeable) import Data.TypeID.Class import Data.TypeID.Error import Data.TypeID.Internal (TypeID'(..))@@ -31,14 +33,13 @@ import Data.UUID.Versions import Foreign import GHC.TypeLits (symbolVal)-import System.Random -- | A TypeID with the prefix encoded at type level. -- -- It is dubbed 'Data.KindID.V7.KindID' because the prefix here is a data kind -- rather than a type. newtype KindID' (version :: UUIDVersion) prefix = KindID' UUID- deriving (Eq, Ord)+ deriving (Eq, Ord, Data, Typeable) instance (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => Show (KindID' version prefix) where@@ -51,9 +52,9 @@ readsPrec :: Int -> String -> [(KindID' version prefix, String)] readsPrec _ str = case TID.parseStringS str of Left _ -> []- Right (tid, rem) -> case fromTypeID tid of+ Right (tid, nks) -> case fromTypeID tid of Nothing -> []- Just kid -> [(kid, rem)]+ Just kid -> [(kid, nks)] {-# INLINE readsPrec #-} instance (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix))
src/Data/KindID/Unsafe.hs view
@@ -4,17 +4,18 @@ -- Maintainer : mmzk1526@outlook.com -- Portability : GHC ----- Unsafe 'KindID' functions.+-- Unsafe 'Data.KindID.V7.KindID' functions. -- -- It is a re-export of "Data.TypeID.V7.Unsafe". -- module Data.KindID.Unsafe (- -- * Unsafe 'KindID' decoding ('KindID'-specific)+ -- * Unsafe 'Data.KindID.V7.KindID' decoding+ -- ('Data.KindID.V7.KindID'-specific) unsafeParseString , unsafeParseText , unsafeParseByteString- -- * Unsafe 'KindID' decoding (class methods)+ -- * Unsafe 'Data.KindID.V7.KindID' decoding (class methods) , unsafeString2ID , unsafeText2ID , unsafeByteString2ID@@ -22,6 +23,4 @@ , unsafeFromTypeID ) where -import Data.KindID.V7 (KindID) import Data.KindID.V7.Unsafe-import Data.TypeID.Class
src/Data/KindID/V1.hs view
@@ -51,13 +51,11 @@ import Control.Monad.IO.Class import Data.ByteString.Lazy (ByteString) import Data.KindID.Class-import Data.KindID.Internal (KindID'(..)) import qualified Data.KindID.Internal as KID import Data.Text (Text) import Data.TypeID.Class import Data.TypeID.Error import Data.TypeID.V1 (TypeIDV1)-import Data.TypeID.V7 (TypeID) import Data.UUID.Types.Internal (UUID) import Data.UUID.Versions
src/Data/KindID/V1/Unsafe.hs view
@@ -22,10 +22,8 @@ import Data.ByteString.Lazy (ByteString) import Data.KindID.Class-import Data.KindID.Internal (KindID') import qualified Data.KindID.Internal as KID import Data.KindID.V1 (KindIDV1)-import Data.TypeID.Internal (TypeID') import Data.TypeID.V1 (TypeIDV1) import Data.Text (Text) import Data.TypeID.Class
src/Data/KindID/V4.hs view
@@ -53,13 +53,11 @@ import Control.Monad.IO.Class import Data.ByteString.Lazy (ByteString) import Data.KindID.Class-import Data.KindID.Internal (KindID'(..)) import qualified Data.KindID.Internal as KID import Data.Text (Text) import Data.TypeID.Class import Data.TypeID.Error import Data.TypeID.V4 (TypeIDV4)-import Data.TypeID.V7 (TypeID) import Data.UUID.Types.Internal (UUID) import Data.UUID.Versions
src/Data/KindID/V4/Unsafe.hs view
@@ -22,10 +22,8 @@ import Data.ByteString.Lazy (ByteString) import Data.KindID.Class-import Data.KindID.Internal (KindID') import qualified Data.KindID.Internal as KID import Data.KindID.V4 (KindIDV4)-import Data.TypeID.Internal (TypeID') import Data.TypeID.V4 (TypeIDV4) import Data.Text (Text) import Data.TypeID.Class
src/Data/KindID/V5.hs view
@@ -51,13 +51,11 @@ import Control.Monad.IO.Class import Data.ByteString.Lazy (ByteString) import Data.KindID.Class-import Data.KindID.Internal (KindID'(..)) import qualified Data.KindID.Internal as KID import Data.Text (Text) import Data.TypeID.Class import Data.TypeID.Error import Data.TypeID.V5 (TypeIDV5)-import Data.TypeID.V7 (TypeID) import Data.UUID.Types.Internal (UUID) import Data.UUID.Versions import Data.Word
src/Data/KindID/V5/Unsafe.hs view
@@ -22,10 +22,8 @@ import Data.ByteString.Lazy (ByteString) import Data.KindID.Class-import Data.KindID.Internal (KindID') import qualified Data.KindID.Internal as KID import Data.KindID.V5 (KindIDV5)-import Data.TypeID.Internal (TypeID') import Data.TypeID.V5 (TypeIDV5) import Data.Text (Text) import Data.TypeID.Class
src/Data/KindID/V7/Unsafe.hs view
@@ -22,10 +22,8 @@ import Data.ByteString.Lazy (ByteString) import Data.KindID.Class-import Data.KindID.Internal (KindID') import qualified Data.KindID.Internal as KID import Data.KindID.V7 (KindID)-import Data.TypeID.Internal (TypeID') import Data.TypeID.V7 (TypeID) import Data.Text (Text) import Data.TypeID.Class@@ -60,9 +58,10 @@ unsafeParseByteString = KID.unsafeParseByteString {-# INLINE unsafeParseByteString #-} --- | Convert a 'TypeID'' to a 'KindID''. If the actual prefix does not match--- with the expected one as defined by the type, it does not complain and--- produces a wrong 'KindID''.+-- | Convert a 'Data.TypeID.Internal.TypeID'' to a+-- 'Data.KindID.Internal.KindID''. If the actual prefix does not match with the+-- expected one as defined by the type, it does not complain and produces a+-- wrong 'Data.KindID.Internal.KindID''. unsafeFromTypeID :: (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => TypeID -> KindID prefix unsafeFromTypeID = KID.unsafeFromTypeID
src/Data/TypeID/Class.hs view
@@ -26,8 +26,8 @@ , checkID , checkIDWithEnv -- * Helper types- , GenFunc(..)- , ResWithErr(..)+ , GenFunc+ , ResWithErr ) where import Control.Exception
src/Data/TypeID/Internal.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE UndecidableInstances #-} -- | -- Module : Data.TypeID.Internal -- License : MIT@@ -23,16 +24,17 @@ import Data.ByteString.Lazy (ByteString) import qualified Data.ByteString.Lazy as BSL import Data.Char+import Data.Data (Data) import Data.Hashable import Data.Proxy import Data.String import Data.Text (Text) import qualified Data.Text as T import Data.Text.Encoding+import Data.Typeable (Typeable) import Data.TypeID.Class import Data.TypeID.Error import Data.UUID.Types.Internal (UUID(..))-import qualified Data.UUID.Types.Internal as UUID import qualified Data.UUID.V1 as V1 import qualified Data.UUID.V4 as V4 import qualified Data.UUID.V5 as V5@@ -47,7 +49,7 @@ -- The constructor is not exposed to the public API to prevent generating -- invalid 'TypeID''s. data TypeID' (version :: UUIDVersion) = TypeID' Text UUID- deriving (Eq, Ord)+ deriving (Eq, Ord, Data, Typeable) instance Show (TypeID' version) where show :: TypeID' version -> String@@ -472,15 +474,15 @@ parseStringS str = case span (/= '_') str of ("", _) -> Left TypeIDExtraSeparator (_, "") -> do- let (uuid, rem) = splitAt 26 str+ let (uuid, nks) = splitAt 26 str bs = fromString uuid- (, rem) . TypeID' "" <$> decodeUUID bs+ (, nks) . TypeID' "" <$> decodeUUID bs (prefix, _ : suffix) -> do let prefix' = T.pack prefix- (uuid, rem) = splitAt 26 suffix+ (uuid, nks) = splitAt 26 suffix bs = fromString uuid case checkPrefix prefix' of- Nothing -> (, rem) . TypeID' prefix' <$> decodeUUID bs+ Nothing -> (, nks) . TypeID' prefix' <$> decodeUUID bs Just err -> Left err -- | Parse a 'TypeID'' from its string representation as a strict 'Text'. It is
src/Data/TypeID/Unsafe.hs view
@@ -4,17 +4,17 @@ -- Maintainer : mmzk1526@outlook.com -- Portability : GHC ----- Unsafe 'TypeID' functions.+-- Unsafe 'Data.TypeID.V7.TypeID' functions. -- -- It is a re-export of "Data.TypeID.V7.Unsafe". -- module Data.TypeID.Unsafe (- -- * Unsafe 'TypeID' generation+ -- * Unsafe 'Data.TypeID.V7.TypeID' generation unsafeGenTypeID , unsafeGenTypeID' , unsafeGenTypeIDs- -- * Unsafe decoding ('TypeID'-specific)+ -- * Unsafe decoding ('Data.TypeID.V7.TypeID'-specific) , unsafeParseString , unsafeParseText , unsafeParseByteString@@ -25,5 +25,4 @@ ) where import Data.TypeID.Class-import Data.TypeID.V7 (TypeID) import Data.TypeID.V7.Unsafe
src/Data/TypeID/V1/Unsafe.hs view
@@ -26,7 +26,6 @@ import Data.TypeID.Class import qualified Data.TypeID.Internal as TID import Data.TypeID.V1 (TypeIDV1)-import Data.UUID.Types.Internal (UUID) -- | Generate a new 'TypeIDV1' from a prefix, but without checking if the prefix -- is valid.
src/Data/TypeID/V4/Unsafe.hs view
@@ -27,7 +27,6 @@ import Data.TypeID.Class import qualified Data.TypeID.Internal as TID import Data.TypeID.V4 (TypeIDV4)-import Data.UUID.Types.Internal (UUID) -- | Generate a new 'TypeIDV4' from a prefix, but without checking if the prefix -- is valid.@@ -35,7 +34,8 @@ unsafeGenTypeID = TID.unsafeGenTypeIDV4 {-# INLINE unsafeGenTypeID #-} --- | Generate a new 'TypeIDV4' from a prefix based on insecure 'UUID'v4.+-- | Generate a new 'TypeIDV4' from a prefix based on insecure+-- 'Data.UUID.Types.Internal.UUID'v4. unsafeGenTypeID' :: MonadIO m => Text -> m TypeIDV4 unsafeGenTypeID' = TID.unsafeGenTypeIDV4' {-# INLINE unsafeGenTypeID' #-}
src/Data/TypeID/V5/Unsafe.hs view
@@ -20,7 +20,6 @@ , unsafeByteString2ID ) where -import Control.Monad.IO.Class import Data.ByteString.Lazy (ByteString) import Data.Text (Text) import Data.TypeID.Class
src/Data/TypeID/V7/Unsafe.hs view
@@ -28,7 +28,6 @@ import Data.TypeID.Class import qualified Data.TypeID.Internal as TID import Data.TypeID.V7 (TypeID)-import Data.UUID.Types.Internal (UUID) import Data.Word -- | Generate a new 'TypeID' from a prefix, but without checking if the prefix@@ -37,8 +36,9 @@ unsafeGenTypeID = TID.unsafeGenTypeID {-# INLINE unsafeGenTypeID #-} --- | Generate a new 'TypeID' from a prefix based on stateless 'UUID'v7, but--- without checking if the prefix is valid.+-- | Generate a new 'TypeID' from a prefix based on stateless +-- 'Data.UUID.Types.Internal.UUID'v7, but without checking if the prefix is+-- valid. unsafeGenTypeID' :: MonadIO m => Text -> m TypeID unsafeGenTypeID' = TID.unsafeGenTypeID' {-# INLINE unsafeGenTypeID' #-}@@ -47,7 +47,8 @@ -- valid. -- -- It tries its best to generate 'TypeID's at the same timestamp, but it may not--- be possible if we are asking too many 'UUID's at the same time.+-- be possible if we are asking too many 'Data.UUID.Types.Internal.UUID's at the+-- same time. -- -- It is guaranteed that the first 32768 'TypeID's are generated at the same -- timestamp.
test/Spec.hs view
@@ -1,7 +1,7 @@-{-# LANGUAGE DeriveAnyClass #-}-{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DuplicateRecordFields #-} +{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}+ import Control.Monad import Data.Aeson import Data.Binary (get, put)@@ -17,7 +17,6 @@ import qualified Data.Map as M import Data.String import Data.Text (Text)-import qualified Data.Text as T import Data.TypeID import Data.TypeID.V1 (TypeIDV1) import Data.TypeID.V4 (TypeIDV4)@@ -125,9 +124,9 @@ , ("long", "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz") , ("ascii", "château") ] describe "can detect invalid prefix" do- forM_ invalidPrefixes \(reason, prefix) -> it reason do- genID @TypeID prefix `shouldThrow` anyTypeIDError- case decorate @TypeID prefix nil of+ forM_ invalidPrefixes \(reason, pref) -> it reason do+ genID @TypeID pref `shouldThrow` anyTypeIDError+ case decorate @TypeID pref nil of Left _ -> pure () Right _ -> expectationFailure "Should not be able to decorate with invalid prefix" let invalidSuffixes = [ ("spaces", " ")@@ -150,10 +149,10 @@ , ("ten", "0000000000000000000000000a", "00000000-0000-0000-0000-00000000000a") , ("sixteen", "0000000000000000000000000g", "00000000-0000-0000-0000-000000000010") , ("thirty-two", "00000000000000000000000010", "00000000-0000-0000-0000-000000000020") ]- forM_ specialValues \(reason, tid, uuid) -> it reason do+ forM_ specialValues \(reason, tid, uid) -> it reason do case string2ID @TypeID tid of- Left err -> expectationFailure $ "Parse error: " ++ show err- Right tid -> show (getUUID tid) `shouldBe` uuid+ Left err -> expectationFailure $ "Parse error: " ++ show err+ Right t -> show (getUUID t) `shouldBe` uid describe "TypeID valid JSON instances" do it "Decode and then encode should be identity" do@@ -164,51 +163,51 @@ decode json `shouldBe` Just mapping fmap encode (decode @(Map TypeID TypeID) json) `shouldBe` Just json describe "Valid JSON value" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case decode @TypeID (fromString $ show tid) of- Nothing -> expectationFailure "Parse JSON failed!"- Just tid -> do- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ Nothing -> expectationFailure "Parse JSON failed!"+ Just t -> do+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "Valid JSON key" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case decode @(Map TypeID Int) (fromString $ "{" ++ show tid ++ ":" ++ "114514" ++ "}") of Nothing -> expectationFailure "Parse JSON failed!" Just mapping -> do- let (tid, _) = M.elemAt 0 mapping- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ let (t, _) = M.elemAt 0 mapping+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "TypeID invalid JSON instances" do describe "Invalid JSON value" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case decode @TypeID (fromString $ show tid) of- Nothing -> pure ()- Just tid -> expectationFailure $ "Parsed TypeID: " ++ show tid+ Nothing -> pure ()+ Just t -> expectationFailure $ "Parsed TypeID: " ++ show t describe "Invalid JSON key" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case decode @(Map TypeID Int) (fromString $ "{" ++ show tid ++ ":" ++ "114514" ++ "}") of- Nothing -> pure ()- Just tid -> expectationFailure "Invalid TypeID key shouldn't be parsed!"+ Nothing -> pure ()+ _ -> expectationFailure "Invalid TypeID key shouldn't be parsed!" describe "Test invalid.json" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case string2ID @TypeID tid of- Left _ -> pure ()- Right tid -> expectationFailure $ "Parsed TypeID: " ++ show tid+ Left _ -> pure ()+ Right t -> expectationFailure $ "Parsed TypeID: " ++ show t describe "Test valid.json (TypeID as literal)" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case string2ID @TypeID tid of- Left err -> expectationFailure $ "Parse error: " ++ show err- Right tid -> do- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ Left err -> expectationFailure $ "Parse error: " ++ show err+ Right t -> do+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "Test valid.json (TypeID as JSON)" do- forM_ validUUID \(TestDataUUID name tid prefix uuid) -> it name do- getPrefix tid `shouldBe` prefix- getUUID tid `shouldBe` uuid+ forM_ validUUID \(TestDataUUID n tid pref uid) -> it n do+ getPrefix tid `shouldBe` pref+ getUUID tid `shouldBe` uid describe "Generate KindID with 'Symbol' prefixes" do it "can generate KindID with prefix" do@@ -240,7 +239,7 @@ Right kid -> getPrefix kid `shouldBe` "mmzk" it "cannot parse KindID into wrong prefix" do case string2ID @(KindID "foo") "mmzk_00041061050r3gg28a1c60t3gf" of- Left err -> pure ()+ Left _ -> pure () Right kid -> expectationFailure $ "Parsed TypeID: " ++ show kid describe "Generate KindID with custom data kind prefixes" do@@ -253,7 +252,7 @@ Right kid -> getPrefix kid `shouldBe` "user" it "cannot parse KindID into wrong prefix" do case string2ID @(KindID 'Comment) "user_00041061050r3gg28a1c60t3gf" of- Left err -> pure ()+ Left _ -> pure () Right kid -> expectationFailure $ "Parsed KindID: " ++ show kid it "can generate in batch with same timestamp and in ascending order" do kids <- withChecks $ genIDs @(KindID 'Comment) 1526@@ -311,7 +310,6 @@ tid <- withCheck $ genID @TypeIDV1 "" getPrefix tid `shouldBe` "" it "can generate TypeIDV1 with insecure UUIDv4" do- start <- V7.getEpochMilli tid <- withCheck $ genID' @TypeIDV1 "mmzk" getPrefix tid `shouldBe` "mmzk" it "can parse TypeIDV1 from String" do@@ -327,9 +325,9 @@ , ("long", "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz") , ("ascii", "château") ] describe "can detect invalid prefix" do- forM_ invalidPrefixes \(reason, prefix) -> it reason do- genID @TypeIDV1 prefix `shouldThrow` anyTypeIDError- case decorate @TypeIDV1 prefix nil of+ forM_ invalidPrefixes \(reason, pref) -> it reason do+ genID @TypeIDV1 pref `shouldThrow` anyTypeIDError+ case decorate @TypeIDV1 pref nil of Left _ -> pure () Right _ -> expectationFailure "Should not be able to decorate with invalid prefix" let invalidSuffixes = [ ("spaces", " ")@@ -352,10 +350,10 @@ , ("ten", "0000000000000000000000000a", "00000000-0000-0000-0000-00000000000a") , ("sixteen", "0000000000000000000000000g", "00000000-0000-0000-0000-000000000010") , ("thirty-two", "00000000000000000000000010", "00000000-0000-0000-0000-000000000020") ]- forM_ specialValues \(reason, tid, uuid) -> it reason do+ forM_ specialValues \(reason, tid, uid) -> it reason do case string2ID @TypeIDV1 tid of- Left err -> expectationFailure $ "Parse error: " ++ show err- Right tid -> show (getUUID tid) `shouldBe` uuid+ Left err -> expectationFailure $ "Parse error: " ++ show err+ Right t -> show (getUUID t) `shouldBe` uid describe "TypeIDV1 valid JSON instances" do it "Decode and then encode should be identity" do@@ -366,51 +364,51 @@ decode json `shouldBe` Just mapping fmap encode (decode @(Map TypeIDV1 TypeIDV1) json) `shouldBe` Just json describe "Valid JSON value" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case decode @TypeIDV1 (fromString $ show tid) of Nothing -> expectationFailure "Parse JSON failed!"- Just tid -> do- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ Just t -> do+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "Valid JSON key" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case decode @(Map TypeIDV1 Int) (fromString $ "{" ++ show tid ++ ":" ++ "114514" ++ "}") of Nothing -> expectationFailure "Parse JSON failed!" Just mapping -> do- let (tid, _) = M.elemAt 0 mapping- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ let (t, _) = M.elemAt 0 mapping+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "TypeIDV1 invalid JSON instances" do describe "Invalid JSON value" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case decode @TypeIDV1 (fromString $ show tid) of- Nothing -> pure ()- Just tid -> expectationFailure $ "Parsed TypeID: " ++ show tid+ Nothing -> pure ()+ Just t -> expectationFailure $ "Parsed TypeID: " ++ show t describe "Invalid JSON key" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case decode @(Map TypeIDV1 Int) (fromString $ "{" ++ show tid ++ ":" ++ "114514" ++ "}") of Nothing -> pure ()- Just tid -> expectationFailure "Invalid TypeID key shouldn't be parsed!"+ _ -> expectationFailure "Invalid TypeID key shouldn't be parsed!" describe "Test invalid.json" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case string2ID @TypeIDV1 tid of- Left _ -> pure ()- Right tid -> expectationFailure $ "Parsed TypeID: " ++ show tid+ Left _ -> pure ()+ Right t -> expectationFailure $ "Parsed TypeID: " ++ show t describe "Test valid.json (TypeIDV1 as literal)" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case string2ID @TypeIDV1 tid of- Left err -> expectationFailure $ "Parse error: " ++ show err- Right tid -> do- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ Left err -> expectationFailure $ "Parse error: " ++ show err+ Right t -> do+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "Test valid.json (TypeIDV1 as JSON)" do- forM_ validUUID \(TestDataUUID name tid prefix uuid) -> it name do- getPrefix tid `shouldBe` prefix- getUUID tid `shouldBe` uuid+ forM_ validUUID \(TestDataUUID n tid pref uid) -> it n do+ getPrefix tid `shouldBe` pref+ getUUID tid `shouldBe` uid describe "Generate KindIDV1 with 'Symbol' prefixes" do it "can generate KindIDV1 with prefix" do@@ -425,7 +423,7 @@ Right kid -> getPrefix kid `shouldBe` "mmzk" it "cannot parse KindID into wrong prefix" do case string2ID @(KindIDV1 "foo") "mmzk_5hjpeh96458fct8t49fnf9farw" of- Left err -> pure ()+ Left _ -> pure () Right kid -> expectationFailure $ "Parsed TypeID: " ++ show kid describe "Generate KindIDV1 with custom data kind prefixes" do@@ -438,7 +436,7 @@ Right kid -> getPrefix kid `shouldBe` "user" it "cannot parse KindIDV1 into wrong prefix" do case string2ID @(KindIDV1 'Comment) "user_00041061050r3gg28a1c60t3gf" of- Left err -> pure ()+ Left _ -> pure () Right kid -> expectationFailure $ "Parsed KindIDV1: " ++ show kid describe "Binary instance for TypeIDV1 and KindIDV1" do@@ -490,7 +488,6 @@ tid <- withCheck $ genID @TypeIDV4 "" getPrefix tid `shouldBe` "" it "can generate TypeIDV4 with insecure UUIDv4" do- start <- V7.getEpochMilli tid <- withCheck $ genID' @TypeIDV4 "mmzk" getPrefix tid `shouldBe` "mmzk" it "can parse TypeIDV4 from String" do@@ -506,9 +503,9 @@ , ("long", "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz") , ("ascii", "château") ] describe "can detect invalid prefix" do- forM_ invalidPrefixes \(reason, prefix) -> it reason do- genID @TypeIDV4 prefix `shouldThrow` anyTypeIDError- case decorate @TypeIDV4 prefix nil of+ forM_ invalidPrefixes \(reason, pref) -> it reason do+ genID @TypeIDV4 pref `shouldThrow` anyTypeIDError+ case decorate @TypeIDV4 pref nil of Left _ -> pure () Right _ -> expectationFailure "Should not be able to decorate with invalid prefix" let invalidSuffixes = [ ("spaces", " ")@@ -531,10 +528,10 @@ , ("ten", "0000000000000000000000000a", "00000000-0000-0000-0000-00000000000a") , ("sixteen", "0000000000000000000000000g", "00000000-0000-0000-0000-000000000010") , ("thirty-two", "00000000000000000000000010", "00000000-0000-0000-0000-000000000020") ]- forM_ specialValues \(reason, tid, uuid) -> it reason do+ forM_ specialValues \(reason, tid, uid) -> it reason do case string2ID @TypeIDV4 tid of- Left err -> expectationFailure $ "Parse error: " ++ show err- Right tid -> show (getUUID tid) `shouldBe` uuid+ Left err -> expectationFailure $ "Parse error: " ++ show err+ Right t -> show (getUUID t) `shouldBe` uid describe "TypeIDV4 valid JSON instances" do it "Decode and then encode should be identity" do@@ -545,51 +542,51 @@ decode json `shouldBe` Just mapping fmap encode (decode @(Map TypeIDV4 TypeIDV4) json) `shouldBe` Just json describe "Valid JSON value" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case decode @TypeIDV4 (fromString $ show tid) of- Nothing -> expectationFailure "Parse JSON failed!"- Just tid -> do- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ Nothing -> expectationFailure "Parse JSON failed!"+ Just t -> do+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "Valid JSON key" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case decode @(Map TypeIDV4 Int) (fromString $ "{" ++ show tid ++ ":" ++ "114514" ++ "}") of Nothing -> expectationFailure "Parse JSON failed!" Just mapping -> do- let (tid, _) = M.elemAt 0 mapping- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ let (t, _) = M.elemAt 0 mapping+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "TypeIDV4 invalid JSON instances" do describe "Invalid JSON value" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case decode @TypeIDV4 (fromString $ show tid) of- Nothing -> pure ()- Just tid -> expectationFailure $ "Parsed TypeID: " ++ show tid+ Nothing -> pure ()+ Just t -> expectationFailure $ "Parsed TypeID: " ++ show t describe "Invalid JSON key" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case decode @(Map TypeIDV4 Int) (fromString $ "{" ++ show tid ++ ":" ++ "114514" ++ "}") of- Nothing -> pure ()- Just tid -> expectationFailure "Invalid TypeID key shouldn't be parsed!"+ Nothing -> pure ()+ _ -> expectationFailure "Invalid TypeID key shouldn't be parsed!" describe "Test invalid.json" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case string2ID @TypeIDV4 tid of- Left _ -> pure ()- Right tid -> expectationFailure $ "Parsed TypeID: " ++ show tid+ Left _ -> pure ()+ Right t -> expectationFailure $ "Parsed TypeID: " ++ show t describe "Test valid.json (TypeIDV4 as literal)" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case string2ID @TypeIDV4 tid of- Left err -> expectationFailure $ "Parse error: " ++ show err- Right tid -> do- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ Left err -> expectationFailure $ "Parse error: " ++ show err+ Right t -> do+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "Test valid.json (TypeIDV4 as JSON)" do- forM_ validUUID \(TestDataUUID name tid prefix uuid) -> it name do- getPrefix tid `shouldBe` prefix- getUUID tid `shouldBe` uuid+ forM_ validUUID \(TestDataUUID n tid pref uid) -> it n do+ getPrefix tid `shouldBe` pref+ getUUID tid `shouldBe` uid describe "Generate KindIDV4 with 'Symbol' prefixes" do it "can generate KindIDV4 with prefix" do@@ -607,7 +604,7 @@ Right kid -> getPrefix kid `shouldBe` "mmzk" it "cannot parse KindID into wrong prefix" do case string2ID @(KindIDV4 "foo") "mmzk_5hjpeh96458fct8t49fnf9farw" of- Left err -> pure ()+ Left _ -> pure () Right kid -> expectationFailure $ "Parsed TypeID: " ++ show kid describe "Generate KindIDV4 with custom data kind prefixes" do@@ -620,7 +617,7 @@ Right kid -> getPrefix kid `shouldBe` "user" it "cannot parse KindIDV4 into wrong prefix" do case string2ID @(KindIDV4 'Comment) "user_00041061050r3gg28a1c60t3gf" of- Left err -> pure ()+ Left _ -> pure () Right kid -> expectationFailure $ "Parsed KindIDV4: " ++ show kid describe "Binary instance for TypeIDV4 and KindIDV4" do@@ -664,13 +661,14 @@ invalid <- runIO (BSL.readFile "test/invalid.json" >>= throwDecode :: IO [TestData]) valid <- runIO (BSL.readFile "test/valid.json" >>= throwDecode :: IO [TestData]) validUUID <- runIO (BSL.readFile "test/valid.json" >>= throwDecode :: IO [TestDataUUID TypeIDV5])- uuid <- runIO nextRandom+ describe "Generate TypeIDV5" do+ uid <- runIO nextRandom it "can generate TypeIDV5 with prefix" do- tid <- withCheck $ genID @TypeIDV5 "mmzk" uuid [11, 45, 14]+ tid <- withCheck $ genID @TypeIDV5 "mmzk" uid [11, 45, 14] getPrefix tid `shouldBe` "mmzk" it "can generate TypeIDV5 without prefix" do- tid <- withCheck $ genID @TypeIDV5 "" uuid [11, 45, 14]+ tid <- withCheck $ genID @TypeIDV5 "" uid [11, 45, 14] getPrefix tid `shouldBe` "" it "can parse TypeIDV5 from String" do case string2ID @TypeIDV5 "mmzk_5hjpeh96458fct8t49fnf9farw" of@@ -678,6 +676,7 @@ Right tid -> getPrefix tid `shouldBe` "mmzk" describe "Parse TypeIDV5" do+ uid <- runIO nextRandom let invalidPrefixes = [ ("caps", "PREFIX") , ("numeric", "12323") , ("symbols", "pre.fix")@@ -685,9 +684,9 @@ , ("long", "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz") , ("ascii", "château") ] describe "can detect invalid prefix" do- forM_ invalidPrefixes \(reason, prefix) -> it reason do- genID @TypeIDV5 prefix uuid [11, 45, 14] `shouldThrow` anyTypeIDError- case decorate @TypeIDV5 prefix nil of+ forM_ invalidPrefixes \(reason, pref) -> it reason do+ genID @TypeIDV5 pref uid [11, 45, 14] `shouldThrow` anyTypeIDError+ case decorate @TypeIDV5 pref nil of Left _ -> pure () Right _ -> expectationFailure "Should not be able to decorate with invalid prefix" let invalidSuffixes = [ ("spaces", " ")@@ -710,72 +709,74 @@ , ("ten", "0000000000000000000000000a", "00000000-0000-0000-0000-00000000000a") , ("sixteen", "0000000000000000000000000g", "00000000-0000-0000-0000-000000000010") , ("thirty-two", "00000000000000000000000010", "00000000-0000-0000-0000-000000000020") ]- forM_ specialValues \(reason, tid, uuid) -> it reason do+ forM_ specialValues \(reason, tid, uid) -> it reason do case string2ID @TypeIDV5 tid of- Left err -> expectationFailure $ "Parse error: " ++ show err- Right tid -> show (getUUID tid) `shouldBe` uuid+ Left err -> expectationFailure $ "Parse error: " ++ show err+ Right t -> show (getUUID t) `shouldBe` uid describe "TypeIDV5 valid JSON instances" do it "Decode and then encode should be identity" do- tid <- genID @TypeIDV5 "mmzk" uuid [11, 45, 14]- tid' <- genID @TypeIDV5 "foo" uuid [11, 45, 14]+ uid <- nextRandom+ tid <- genID @TypeIDV5 "mmzk" uid [11, 45, 14]+ tid' <- genID @TypeIDV5 "foo" uid [11, 45, 14] let mapping = M.fromList [(tid, tid')] let json = encode mapping decode json `shouldBe` Just mapping fmap encode (decode @(Map TypeIDV5 TypeIDV5) json) `shouldBe` Just json describe "Valid JSON value" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case decode @TypeIDV5 (fromString $ show tid) of- Nothing -> expectationFailure "Parse JSON failed!"- Just tid -> do- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ Nothing -> expectationFailure "Parse JSON failed!"+ Just t -> do+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "Valid JSON key" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case decode @(Map TypeIDV5 Int) (fromString $ "{" ++ show tid ++ ":" ++ "114514" ++ "}") of Nothing -> expectationFailure "Parse JSON failed!" Just mapping -> do- let (tid, _) = M.elemAt 0 mapping- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ let (t, _) = M.elemAt 0 mapping+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "TypeIDV5 invalid JSON instances" do describe "Invalid JSON value" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case decode @TypeIDV5 (fromString $ show tid) of- Nothing -> pure ()- Just tid -> expectationFailure $ "Parsed TypeID: " ++ show tid+ Nothing -> pure ()+ Just t -> expectationFailure $ "Parsed TypeID: " ++ show t describe "Invalid JSON key" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case decode @(Map TypeIDV5 Int) (fromString $ "{" ++ show tid ++ ":" ++ "114514" ++ "}") of- Nothing -> pure ()- Just tid -> expectationFailure "Invalid TypeID key shouldn't be parsed!"+ Nothing -> pure ()+ _ -> expectationFailure "Invalid TypeID key shouldn't be parsed!" describe "Test invalid.json" do- forM_ invalid \(TestData name tid _ _) -> it name do+ forM_ invalid \(TestData n tid _ _) -> it n do case string2ID @TypeIDV5 tid of Left _ -> pure ()- Right tid -> expectationFailure $ "Parsed TypeID: " ++ show tid+ Right t -> expectationFailure $ "Parsed TypeID: " ++ show t describe "Test valid.json (TypeIDV5 as literal)" do- forM_ valid \(TestData name tid (Just prefix) (Just uuid)) -> it name do+ forM_ valid \(TestData n tid (Just pref) (Just uid)) -> it n do case string2ID @TypeIDV5 tid of- Left err -> expectationFailure $ "Parse error: " ++ show err- Right tid -> do- getPrefix tid `shouldBe` prefix- show (getUUID tid) `shouldBe` uuid+ Left err -> expectationFailure $ "Parse error: " ++ show err+ Right t -> do+ getPrefix t `shouldBe` pref+ show (getUUID t) `shouldBe` uid describe "Test valid.json (TypeIDV5 as JSON)" do- forM_ validUUID \(TestDataUUID name tid prefix uuid) -> it name do- getPrefix tid `shouldBe` prefix- getUUID tid `shouldBe` uuid+ forM_ validUUID \(TestDataUUID n tid pref uid) -> it n do+ getPrefix tid `shouldBe` pref+ getUUID tid `shouldBe` uid describe "Generate KindIDV5 with 'Symbol' prefixes" do+ uid <- runIO nextRandom it "can generate KindIDV5 with prefix" do- kid <- withCheck $ genID @(KindIDV5 "mmzk") uuid [11, 45, 14]+ kid <- withCheck $ genID @(KindIDV5 "mmzk") uid [11, 45, 14] getPrefix kid `shouldBe` "mmzk" it "can generate KindIDV5 without prefix" do- kid <- withCheck $ genID @(KindIDV5 "") uuid [11, 45, 14]+ kid <- withCheck $ genID @(KindIDV5 "") uid [11, 45, 14] getPrefix kid `shouldBe` "" it "can parse KindID from String" do case string2ID @(KindIDV5 "mmzk") "mmzk_5hjpeh96458fct8t49fnf9farw" of@@ -783,7 +784,7 @@ Right kid -> getPrefix kid `shouldBe` "mmzk" it "cannot parse KindID into wrong prefix" do case string2ID @(KindIDV5 "foo") "mmzk_5hjpeh96458fct8t49fnf9farw" of- Left err -> pure ()+ Left _ -> pure () Right kid -> expectationFailure $ "Parsed TypeID: " ++ show kid describe "Generate KindIDV5 with custom data kind prefixes" do@@ -796,26 +797,28 @@ Right kid -> getPrefix kid `shouldBe` "user" it "cannot parse KindIDV5 into wrong prefix" do case string2ID @(KindIDV5 'Comment) "user_00041061050r3gg28a1c60t3gf" of- Left err -> pure ()+ Left _ -> pure () Right kid -> expectationFailure $ "Parsed KindIDV5: " ++ show kid describe "Binary instance for TypeIDV5 and KindIDV5" do+ uid <- runIO nextRandom it "has correct binary instance for TypeIDV5" do- tids <- withChecks $ genIDs @TypeIDV5 "abcdefghijklmnopqrstuvwxyz" uuid [11, 45, 14] 114+ tids <- withChecks $ genIDs @TypeIDV5 "abcdefghijklmnopqrstuvwxyz" uid [11, 45, 14] 114 forM_ tids \tid -> do let bytes = runPut (put tid) let tid' = runGet get bytes tid' `shouldBe` tid it "has correct binary instance for KindIDV5" do- kids <- withChecks $ genIDs @(KindIDV5 "abcdefghijklmnopqrstuvwxyz") uuid [11, 45, 14] 114+ kids <- withChecks $ genIDs @(KindIDV5 "abcdefghijklmnopqrstuvwxyz") uid [11, 45, 14] 114 forM_ kids \kid -> do let bytes = runPut (put kid) let kid' = runGet get bytes kid' `shouldBe` kid describe "Storable instance for TypeIDV5 and KindIDV5" do+ uid <- runIO nextRandom it "has correct Storable instance for TypeIDV5" do- tids <- withChecks $ genIDs @TypeIDV5 "abcdefghijklmnopqrstuvwxyz" uuid [11, 45, 14] 114+ tids <- withChecks $ genIDs @TypeIDV5 "abcdefghijklmnopqrstuvwxyz" uid [11, 45, 14] 114 forM_ tids \tid -> do ptr <- new tid tid' <- peek ptr@@ -825,7 +828,7 @@ tid'' `shouldBe` tid' free ptr it "has correct Storable instance for KindIDV5" do- kids <- withChecks $ genIDs @(KindIDV5 "abcdefghijklmnopqrstuvwxyz") uuid [11, 45, 14] 114+ kids <- withChecks $ genIDs @(KindIDV5 "abcdefghijklmnopqrstuvwxyz") uid [11, 45, 14] 114 forM_ kids \kid -> do ptr <- new kid kid' <- peek ptr