mmzk-typeid-0.2.0.0: A TypeID implementation for Haskell
LicenseMIT
Maintainermmzk1526@outlook.com
PortabilityGHC
Safe HaskellSafe-Inferred
LanguageHaskell2010

Data.KindID

Description

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.

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 one table in the database.

For example, suppose we have a function that takes a KindID with the prefix "user", it may have a signature like this: f :: KindID "user" -> IO ()

Then if we try to pass in a KindID with the prefix "post", the compiler will complain, thus removing the runtime check and the associated overhead.

All the prefixes are type-checked at compile time, so if we try to pass in invalid prefixes, the compiler (again) will complain.

This module contains functions to generate and parse these type-level TypeIDs as well as conversion functions to and from the usual term-level TypeIDs. These functions are usually used with a type application, e.g.

do
  tid <- genKindID @"user"
  ...
Synopsis

Data types

data KindID prefix Source #

A TypeID with the prefix encoded at type level.

It is dubbed KindID because we the prefix here is a data kind rather than a type.

Note that the Show instance is for debugging purposes only. To pretty-print a KindID, use toString, toText or toByteString. However, this behaviour will be changed in the next major version as it is not useful. By then, the Show instance will be the same as toString.

Instances

Instances details
Show (KindID prefix) Source # 
Instance details

Defined in Data.KindID.Internal

Methods

showsPrec :: Int -> KindID prefix -> ShowS #

show :: KindID prefix -> String #

showList :: [KindID prefix] -> ShowS #

Eq (KindID prefix) Source # 
Instance details

Defined in Data.KindID.Internal

Methods

(==) :: KindID prefix -> KindID prefix -> Bool #

(/=) :: KindID prefix -> KindID prefix -> Bool #

Ord (KindID prefix) Source # 
Instance details

Defined in Data.KindID.Internal

Methods

compare :: KindID prefix -> KindID prefix -> Ordering #

(<) :: KindID prefix -> KindID prefix -> Bool #

(<=) :: KindID prefix -> KindID prefix -> Bool #

(>) :: KindID prefix -> KindID prefix -> Bool #

(>=) :: KindID prefix -> KindID prefix -> Bool #

max :: KindID prefix -> KindID prefix -> KindID prefix #

min :: KindID prefix -> KindID prefix -> KindID prefix #

(ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => IDConv (KindID prefix) Source #

Conversion between KindID and StringTextByteString.

Instance details

Defined in Data.KindID.Internal

(ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => IDType (KindID prefix) Source #

Get the prefix, UUID, and timestamp of a KindID.

Instance details

Defined in Data.KindID.Internal

Methods

getPrefix :: KindID prefix -> Text Source #

getUUID :: KindID prefix -> UUID Source #

getTime :: KindID prefix -> Word64 Source #

(ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => FromJSON (KindID prefix) Source # 
Instance details

Defined in Data.KindID.Internal

Methods

parseJSON :: Value -> Parser (KindID prefix) #

parseJSONList :: Value -> Parser [KindID prefix] #

omittedField :: Maybe (KindID prefix) #

(ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => FromJSONKey (KindID prefix) Source # 
Instance details

Defined in Data.KindID.Internal

(ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => ToJSON (KindID prefix) Source # 
Instance details

Defined in Data.KindID.Internal

Methods

toJSON :: KindID prefix -> Value #

toEncoding :: KindID prefix -> Encoding #

toJSONList :: [KindID prefix] -> Value #

toEncodingList :: [KindID prefix] -> Encoding #

omitField :: KindID prefix -> Bool #

(ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => ToJSONKey (KindID prefix) Source # 
Instance details

Defined in Data.KindID.Internal

getPrefix :: IDType a => a -> Text Source #

Get the prefix of the identifier.

getUUID :: IDType a => a -> UUID Source #

Get the UUID suffix of the identifier.

getTime :: IDType a => a -> Word64 Source #

Get the timestamp of the identifier.

type ValidPrefix prefix = (KnownSymbol prefix, LengthSymbol prefix < 64, IsLowerSymbol prefix ~ 'True) Source #

A constraint for valid prefix Symbols.

class ToPrefix a Source #

A class that translates any kind to a Symbol. It is used to translate custom data kinds to a Symbol so that they can be used as KindID prefixes.

For example, suppose we have the following data structure that represents the prefixes we are going to use:

data Prefix = User | Post | Comment

Then we can make it an instance of ToPrefix like this:

instance ToPrefix 'User where
  type PrefixSymbol 'User = "user"

instance ToPrefix 'Post where
  type PrefixSymbol 'Post = "post"

instance ToPrefix 'Comment where
  type PrefixSymbol 'Comment = "comment"

Now we can use Prefix as a prefix for KindIDs, e.g.

do
  userID <- genKindID @'User -- Same as genKindID @"user"
  postID <- genKindID @'Post -- Same as genKindID @"post"
  commentID <- genKindID @'Comment -- Same as genKindID @"comment"

Associated Types

type PrefixSymbol a :: Symbol Source #

Instances

Instances details
ToPrefix (a :: Symbol) Source #

The PrefixSymbol of a Symbol is the Symbol itself.

Instance details

Defined in Data.KindID.Internal

Associated Types

type PrefixSymbol a :: Symbol Source #

KindID generation

nil :: KindID "" Source #

Deprecated: Use nilKindID instead.

The nil KindID.

genKindID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => IO (KindID prefix) Source #

Generate a new KindID from a prefix.

It throws a TypeIDError if the prefix does not match the specification, namely if it's longer than 63 characters or if it contains characters other than lowercase latin letters.

genKindIDs :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => Word16 -> IO [KindID prefix] Source #

Generate n KindIDs from a prefix.

It tries its best to generate KindIDs at the same timestamp, but it may not be possible if we are asking too many UUIDs at the same time.

It is guaranteed that the first 32768 KindIDs are generated at the same timestamp.

decorate :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => UUID -> KindID prefix Source #

Deprecated: Use decorateKindID instead.

Obtain a KindID from a prefix and a UUID.

decorateKindID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => UUID -> KindID prefix Source #

Obtain a KindID from a prefix and a UUID.

Encoding & decoding (class methods)

id2String :: IDConv a => a -> String Source #

Pretty-print the identifier to a String.

id2Text :: IDConv a => a -> Text Source #

Pretty-print the identifier to a strict Text.

id2ByteString :: IDConv a => a -> ByteString Source #

Pretty-print the identifier to a lazy ByteString.

string2ID :: IDConv a => String -> Either TypeIDError a Source #

Parse the identifier from its String representation.

text2ID :: IDConv a => Text -> Either TypeIDError a Source #

Parse the identifier from its string representation as a strict Text.

byteString2ID :: IDConv a => ByteString -> Either TypeIDError a Source #

Parse the identifier from its string representation as a lazy ByteString.

Encoding & decoding (KindID-specific)

toString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> String Source #

Pretty-print a KindID. It is id2String with concrete type.

toText :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> Text Source #

Pretty-print a KindID to strict Text. It is id2Text with concrete type.

toByteString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> ByteString Source #

Pretty-print a KindID to lazy ByteString. It is id2ByteString with concrete type.

parseString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => String -> Either TypeIDError (KindID prefix) Source #

Parse a KindID from its String representation. It is parseString with concrete type.

parseText :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => Text -> Either TypeIDError (KindID prefix) Source #

Parse a KindID from its string representation as a strict Text. It is parseText with concrete type.

parseByteString :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => ByteString -> Either TypeIDError (KindID prefix) Source #

Parse a KindID from its string representation as a lazy ByteString. It is parseByteString with concrete type.

Type-level & term-level conversion

toTypeID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => KindID prefix -> TypeID Source #

Convert a KindID to a TypeID.

fromTypeID :: forall prefix. (ToPrefix prefix, ValidPrefix (PrefixSymbol prefix)) => TypeID -> Maybe (KindID prefix) Source #

Convert a TypeID to a KindID. If the actual prefix does not match with the expected one as defined by the type, it returns Nothing.