2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE TemplateHaskell #-}
4{-# OPTIONS_GHC -Wno-orphans #-}
7 ( Id, mkId, unId, randomId, unsafeIdTagConvert, coerceId, nilId
8 , IntId, mkIntId, unIntId, unsafeIntIdTagConvert, coerceIntId
9 , Name, mkName, unName, unsafeNameTagConvert, coerceName
16import Control.DeepSeq (NFData)
21import Data.Aeson (FromJSON, FromJSONKey, ToJSON, ToJSONKey)
22import Data.Binary (Binary)
23import Data.Coerce (coerce)
25import Data.Hashable (Hashable)
26import Data.Int (Int64)
32import Data.UUID (UUID)
33import qualified Data.UUID as UUID
34import qualified Data.UUID.V4 as UUID.V4
37import Data.Csv as Csv hiding(Name)
40import Database.PostgreSQL.Simple.FromField as PG (FromField)
41import Database.PostgreSQL.Simple.ToField as PG (ToField)
46import Text.ParserCombinators.ReadP
48import Web.PathPieces (PathPiece(..))
53import qualified Data.Store
56import Rel8 (DBType(..), DBEq(..))
59newtype Id t = Id { unId :: UUID }
65 , PG.ToField, PG.FromField
71 , FromJSON, ToJSON, NFData, Hashable, FromJSONKey, ToJSONKey
73 , ToSchema, ToParamSchema
75 , FromHttpApiData, ToHttpApiData )
79mkId :: forall s. UUID -> Id s
83randomId :: forall s. IO (Id s)
84randomId = coerce <$> UUID.V4.nextRandom
85{-# INLINE randomId #-}
87instance KnownSymbol s => Show (Id s) where
88 show (Id v) = "Id-" <> symbolVal (Proxy @s) <> "-" <> show v
90instance KnownSymbol s => Read (Id s) where
91 readsPrec _ = readP_to_S $ do
92 _ <- string ("Id-" <> symbolVal (Proxy @s) <> "-")
93 mkId <$> readS_to_P reads
96instance Flat (Id s) where
97 encode = F.encode . UUID.toWords . coerce
98 decode = coerce . (\(a,b,c,d) -> UUID.fromWords a b c d) <$> F.decode
99 size = F.size . UUID.toWords . coerce
103instance Data.Store.Store (Id s) where
104 poke = Data.Store.poke . UUID.toWords . coerce
105 peek = coerce . (\(a,b,c,d) -> UUID.fromWords a b c d) <$> Data.Store.peek
106 size = Data.Store.ConstSize 16
109instance Arbitrary (Id t) where
110 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 Int64
157 , PG.ToField, PG.FromField
160 , Csv.ToField, Csv.FromField
172 , FromJSON, ToJSON, NFData, Hashable, FromJSONKey, ToJSONKey
174 , ToSchema, ToParamSchema
176 , FromHttpApiData, ToHttpApiData, PathPiece, Arbitrary
177 , Num, Integral, Real, Enum )
179type role IntId nominal
181mkIntId :: forall s. Integer -> IntId s
183{-# INLINE mkIntId #-}
185unIntId :: IntId s -> Integer
186unIntId (IntId i) = fromIntegral i
187{-# INLINE unIntId #-}
189instance KnownSymbol s => Show (IntId s) where
190 show (IntId v) = "IntId-" <> symbolVal (Proxy @s) <> "-" <> show v
192instance KnownSymbol s => Read (IntId s) where
193 readsPrec _ = readP_to_S $ do
194 _ <- string ("IntId-" <> symbolVal (Proxy @s) <> "-")
195 mkIntId <$> readS_to_P reads
197-- | This is a more \"explicit\" 'coerce' specifically for 'IntId'.
198-- You are forced to explicitly specify the phantom types you are converting
199-- via the @TypeApplications@ compiler extension.
200coerceIntId, unsafeIntIdTagConvert
201 :: forall a b. IntId (Ambiguous a) -> IntId (Ambiguous b)
203{-# INLINE coerceIntId #-}
204unsafeIntIdTagConvert = coerce
205{-# INLINE unsafeIntIdTagConvert #-}
207----------------- Name
208newtype Name t = Name { unName :: Text }
214 , PG.ToField, PG.FromField
217 , Csv.ToField, Csv.FromField
229 , FromJSON, ToJSON, NFData, Hashable, FromJSONKey, ToJSONKey
231 , ToSchema, ToParamSchema
233 , FromHttpApiData, ToHttpApiData, PathPiece
234 , IsString, Semigroup, Monoid )
236type role Name nominal
238mkName :: forall s. Text -> Name s
242instance KnownSymbol s => Show (Name s) where
243 show (Name v) = "Name-" <> symbolVal (Proxy @s) <> "-" <> show v
245instance KnownSymbol s => Read (Name s) where
246 readsPrec _ = readP_to_S $ do
247 _ <- string ("Name-" <> symbolVal (Proxy @s) <> "-")
248 mkName <$> readS_to_P reads
250instance Arbitrary (Name s) where
251 arbitrary = coerce . T.pack . getPrintableString <$> arbitrary
253-- | This is a more \"explicit\" 'coerce' specifically for 'Name'.
254-- You are forced to explicitly specify the phantom types you are converting
255-- via the @TypeApplications@ compiler extension.
256coerceName, unsafeNameTagConvert
257 :: forall a b. Name (Ambiguous a) -> Name (Ambiguous b)
259{-# INLINE coerceName #-}
260unsafeNameTagConvert = coerce
261{-# 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