2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE TemplateHaskell #-}
4{-# OPTIONS_GHC -Wno-orphans #-}
7 ( Id, mkId, unId, unsafeIdTagConvert, coerceId, _Id, nilId
8 , IntId, mkIntId, unIntId, unsafeIntIdTagConvert, coerceIntId, _IntId
9 , Name, mkName, unName, unsafeNameTagConvert, coerceName, _Name
16import Control.DeepSeq (NFData)
19import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey)
20import Data.Binary (Binary)
21import Data.Coerce (coerce)
23import Data.Hashable (Hashable)
26import Data.UUID.Types (UUID)
27import qualified Data.UUID.Types as UUID
30import Text.ParserCombinators.ReadP
32import Web.PathPieces (PathPiece(..))
35import qualified Data.UUID.V4 as UUID.V4
41import Data.Csv as Csv hiding(Name)
44import Database.PostgreSQL.Simple.FromField as PG (FromField)
45import Database.PostgreSQL.Simple.ToField as PG (ToField)
53import qualified Data.Store
56newtype Id t = Id { unId :: UUID }
62 , PG.ToField, PG.FromField
65 , FromJSON, ToJSON, NFData, Hashable, FromJSONKey, ToJSONKey
67 , ToSchema, ToParamSchema
69 , FromHttpApiData, ToHttpApiData )
75mkId :: forall s. UUID -> Id s
80randomId :: forall s. IO (Id s)
81randomId = coerce <$> UUID.V4.nextRandom
82{-# INLINE randomId #-}
85instance KnownSymbol s => Show (Id s) where
86 show (Id v) = "Id-" <> symbolVal (Proxy @s) <> "-" <> P.show v
88instance KnownSymbol s => Read (Id s) where
89 readsPrec _ = readP_to_S $ do
90 _ <- string ("Id-" <> symbolVal (Proxy @s) <> "-")
91 mkId <$> readS_to_P reads
94instance Flat (Id s) where
95 encode = F.encode . UUID.toWords . coerce
96 decode = coerce . (\(a,b,c,d) -> UUID.fromWords a b c d) <$> F.decode
97 size = F.size . UUID.toWords . coerce
101instance Data.Store.Store (Id s) where
102 poke = Data.Store.poke . UUID.toWords . coerce
103 peek = coerce . (\(a,b,c,d) -> UUID.fromWords a b c d) <$> Data.Store.peek
104 size = Data.Store.ConstSize 16
108instance Arbitrary (Id t) where
109 arbitrary = fmap Id $ UUID.fromWords
116instance PathPiece (Id t) where
117 fromPathPiece = coerce . UUID.fromText
118 toPathPiece = UUID.toText . coerce
123instance Csv.FromField (Id tag) where
124 parseField = parseField
125 >=> fmap mkId . maybe (fail "invalid UUID in CSV") pure . UUID.fromText
127instance Csv.ToField (Id tag) where
128 toField = Csv.toField . UUID.toText . coerce
133-- | This is a more \"explicit\" 'coerce' specifically for 'Id'.
134-- You are forced to explicitly specify the phantom types you are converting
135-- via the @TypeApplications@ compiler extension.
136coerceId, unsafeIdTagConvert :: forall a b. Id (Ambiguous a) -> Id (Ambiguous b)
138{-# INLINE coerceId #-}
139unsafeIdTagConvert = coerce
140{-# INLINE unsafeIdTagConvert #-}
142-- | Id corresponding to UUID nil. Useful for testing etc.
143nilId :: forall a. Id (Ambiguous a)
146-- https://kcsongor.github.io/ambiguous-tags/
147type family Ambiguous (a :: k) :: j where
150----------------- IntId
151newtype IntId t = IntId { unIntId :: Integer }
157 , PG.ToField, PG.FromField
160 , Csv.ToField, Csv.FromField
170 , ToSchema, ToParamSchema, Arbitrary
172 , FromJSON, ToJSON, NFData, Hashable, FromJSONKey, ToJSONKey, FromHttpApiData
173 , ToHttpApiData, PathPiece, Num, Integral, Real, Enum )
175type role IntId nominal
179mkIntId :: forall s. Integer -> IntId s
181{-# INLINE mkIntId #-}
183instance KnownSymbol s => Show (IntId s) where
184 show (IntId v) = "IntId-" <> symbolVal (Proxy @s) <> "-" <> P.show v
186instance KnownSymbol s => Read (IntId s) where
187 readsPrec _ = readP_to_S $ do
188 _ <- string ("IntId-" <> symbolVal (Proxy @s) <> "-")
189 mkIntId <$> readS_to_P reads
191-- | This is a more \"explicit\" 'coerce' specifically for 'IntId'.
192-- You are forced to explicitly specify the phantom types you are converting
193-- via the @TypeApplications@ compiler extension.
194coerceIntId, unsafeIntIdTagConvert
195 :: forall a b. IntId (Ambiguous a) -> IntId (Ambiguous b)
197{-# INLINE coerceIntId #-}
198unsafeIntIdTagConvert = coerce
199{-# INLINE unsafeIntIdTagConvert #-}
201----------------- Name
202newtype Name t = Name { unName :: Text }
208 , PG.ToField, PG.FromField
211 , Csv.ToField, Csv.FromField
221 , ToSchema, ToParamSchema
223 , FromJSON, ToJSON, NFData, Hashable, FromJSONKey, ToJSONKey, FromHttpApiData
224 , ToHttpApiData, PathPiece, IsString, Semigroup, Monoid )
226type role Name nominal
230mkName :: forall s. Text -> Name s
234instance KnownSymbol s => Show (Name s) where
235 show (Name v) = "Name-" <> symbolVal (Proxy @s) <> "-" <> P.show v
237instance KnownSymbol s => Read (Name s) where
238 readsPrec _ = readP_to_S $ do
239 _ <- string ("Name-" <> symbolVal (Proxy @s) <> "-")
240 mkName <$> readS_to_P reads
243instance Arbitrary (Name s) where
244 arbitrary = coerce . T.pack . getPrintableString <$> arbitrary
247-- | This is a more \"explicit\" 'coerce' specifically for 'Name'.
248-- You are forced to explicitly specify the phantom types you are converting
249-- via the @TypeApplications@ compiler extension.
250coerceName, unsafeNameTagConvert
251 :: forall a b. Name (Ambiguous a) -> Name (Ambiguous b)
253{-# INLINE coerceName #-}
254unsafeNameTagConvert = coerce
255{-# INLINE unsafeNameTagConvert #-}
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list