dynamodb-simple 0.4.0.0 → 0.5.0.0
raw patch · 8 files changed
+62/−16 lines, 8 filesdep +uuid-typesdep ~amazonka-dynamodbdep ~bytestringPVP ok
version bump matches the API change (PVP)
Dependencies added: uuid-types
Dependency ranges changed: amazonka-dynamodb, bytestring
API changes (from Hackage documentation)
+ Database.DynamoDB: querySourceByKey :: forall a parent hash rest v1 m r. (DynamoIndex a parent NoRange, Code a ~ '[hash : rest], DynamoScalar v1 hash, MonadAWS m, DynamoTable parent r) => Proxy a -> hash -> Source m a
+ Database.DynamoDB.Types: instance Database.DynamoDB.Types.DynamoEncodable Data.UUID.Types.Internal.UUID
+ Database.DynamoDB.Types: instance Database.DynamoDB.Types.DynamoScalar 'Network.AWS.DynamoDB.Types.Sum.S Data.UUID.Types.Internal.UUID
- Database.DynamoDB: qConsistentRead :: forall a_a15F6 hash_a15F7 range_a15F8. Lens' (QueryOpts a_a15F6 hash_a15F7 range_a15F8) Consistency
+ Database.DynamoDB: qConsistentRead :: forall a_a18KQ hash_a18KR range_a18KS. Lens' (QueryOpts a_a18KQ hash_a18KR range_a18KS) Consistency
- Database.DynamoDB: qDirection :: forall a_a15F6 hash_a15F7 range_a15F8. Lens' (QueryOpts a_a15F6 hash_a15F7 range_a15F8) Direction
+ Database.DynamoDB: qDirection :: forall a_a18KQ hash_a18KR range_a18KS. Lens' (QueryOpts a_a18KQ hash_a18KR range_a18KS) Direction
- Database.DynamoDB: qFilterCondition :: forall a_a15F6 hash_a15F7 range_a15F8 a_a15HJ. Lens (QueryOpts a_a15F6 hash_a15F7 range_a15F8) (QueryOpts a_a15HJ hash_a15F7 range_a15F8) (Maybe (FilterCondition a_a15F6)) (Maybe (FilterCondition a_a15HJ))
+ Database.DynamoDB: qFilterCondition :: forall a_a18KQ hash_a18KR range_a18KS a_a18Nt. Lens (QueryOpts a_a18KQ hash_a18KR range_a18KS) (QueryOpts a_a18Nt hash_a18KR range_a18KS) (Maybe (FilterCondition a_a18KQ)) (Maybe (FilterCondition a_a18Nt))
- Database.DynamoDB: qHashKey :: forall a_a15F6 hash_a15F7 range_a15F8. Lens' (QueryOpts a_a15F6 hash_a15F7 range_a15F8) hash_a15F7
+ Database.DynamoDB: qHashKey :: forall a_a18KQ hash_a18KR range_a18KS. Lens' (QueryOpts a_a18KQ hash_a18KR range_a18KS) hash_a18KR
- Database.DynamoDB: qLimit :: forall a_a15F6 hash_a15F7 range_a15F8. Lens' (QueryOpts a_a15F6 hash_a15F7 range_a15F8) (Maybe Natural)
+ Database.DynamoDB: qLimit :: forall a_a18KQ hash_a18KR range_a18KS. Lens' (QueryOpts a_a18KQ hash_a18KR range_a18KS) (Maybe Natural)
- Database.DynamoDB: qRangeCondition :: forall a_a15F6 hash_a15F7 range_a15F8. Lens' (QueryOpts a_a15F6 hash_a15F7 range_a15F8) (Maybe (RangeOper range_a15F8))
+ Database.DynamoDB: qRangeCondition :: forall a_a18KQ hash_a18KR range_a18KS. Lens' (QueryOpts a_a18KQ hash_a18KR range_a18KS) (Maybe (RangeOper range_a18KS))
- Database.DynamoDB: qStartKey :: forall a_a15F6 hash_a15F7 range_a15F8. Lens' (QueryOpts a_a15F6 hash_a15F7 range_a15F8) (Maybe (hash_a15F7, range_a15F8))
+ Database.DynamoDB: qStartKey :: forall a_a18KQ hash_a18KR range_a18KS. Lens' (QueryOpts a_a18KQ hash_a18KR range_a18KS) (Maybe (hash_a18KR, range_a18KS))
- Database.DynamoDB: sConsistentRead :: forall a_a15Jd r_a15Je. Lens' (ScanOpts a_a15Jd r_a15Je) Consistency
+ Database.DynamoDB: sConsistentRead :: forall a_a18OZ r_a18P0. Lens' (ScanOpts a_a18OZ r_a18P0) Consistency
- Database.DynamoDB: sFilterCondition :: forall a_a15Jd r_a15Je. Lens' (ScanOpts a_a15Jd r_a15Je) (Maybe (FilterCondition a_a15Jd))
+ Database.DynamoDB: sFilterCondition :: forall a_a18OZ r_a18P0. Lens' (ScanOpts a_a18OZ r_a18P0) (Maybe (FilterCondition a_a18OZ))
- Database.DynamoDB: sLimit :: forall a_a15Jd r_a15Je. Lens' (ScanOpts a_a15Jd r_a15Je) (Maybe Natural)
+ Database.DynamoDB: sLimit :: forall a_a18OZ r_a18P0. Lens' (ScanOpts a_a18OZ r_a18P0) (Maybe Natural)
- Database.DynamoDB: sParallel :: forall a_a15Jd r_a15Je. Lens' (ScanOpts a_a15Jd r_a15Je) (Maybe (Natural, Natural))
+ Database.DynamoDB: sParallel :: forall a_a18OZ r_a18P0. Lens' (ScanOpts a_a18OZ r_a18P0) (Maybe (Natural, Natural))
- Database.DynamoDB: sStartKey :: forall a_a15Jd r_a15Je r_a16oc. Lens (ScanOpts a_a15Jd r_a15Je) (ScanOpts a_a15Jd r_a16oc) (Maybe (PrimaryKey a_a15Jd r_a15Je)) (Maybe (PrimaryKey a_a15Jd r_a16oc))
+ Database.DynamoDB: sStartKey :: forall a_a18OZ r_a18P0 r_a19yR. Lens (ScanOpts a_a18OZ r_a18P0) (ScanOpts a_a18OZ r_a19yR) (Maybe (PrimaryKey a_a18OZ r_a18P0)) (Maybe (PrimaryKey a_a18OZ r_a19yR))
- Database.DynamoDB.Types: scalarDecode :: (DynamoScalar v a, Show a, Read a) => ScalarValue S -> Maybe a
+ Database.DynamoDB.Types: scalarDecode :: (DynamoScalar v a, Show a, Read a, v ~ S) => ScalarValue v -> Maybe a
- Database.DynamoDB.Types: scalarEncode :: (DynamoScalar v a, Show a, Read a) => a -> ScalarValue S
+ Database.DynamoDB.Types: scalarEncode :: (DynamoScalar v a, Show a, Read a, v ~ S) => a -> ScalarValue v
Files
- changelog.md +6/−0
- dynamodb-simple.cabal +4/−4
- src/Database/DynamoDB.hs +1/−0
- src/Database/DynamoDB/Class.hs +1/−4
- src/Database/DynamoDB/Migration.hs +1/−0
- src/Database/DynamoDB/QueryRequest.hs +24/−4
- src/Database/DynamoDB/Types.hs +12/−2
- test/BaseSpec.hs +13/−2
changelog.md view
@@ -1,8 +1,14 @@+# 0.4.0.1++- Fixed default signatures to compile with GHC 8.2+ # 0.4.0.0+ - Slightly changed TH API to allow table prefixing - Better consistency settings detection for queryOverIndex # 0.3.0.0+ - API changes regarding position of `Proxy` - Added index->table conversion functions - Added conduits for left/inner join
dynamodb-simple.cabal view
@@ -1,5 +1,5 @@ name: dynamodb-simple-version: 0.4.0.0+version: 0.5.0.0 synopsis: Typesafe library for working with DynamoDB database description: Framework for accessing DynamoDB database. The majority of AWS API is available to the user in a convenient, simple and typesafe manner.@@ -27,13 +27,13 @@ Database.DynamoDB.Internal, Database.DynamoDB.BatchRequest, Database.DynamoDB.QueryRequest, Database.DynamoDB.THLens, Database.DynamoDB.THContains, Database.DynamoDB.THConvert- build-depends: base >=4.8 && <5, amazonka-dynamodb, generics-sop,+ build-depends: base >=4.8 && <5, amazonka-dynamodb >= 1.4.5, generics-sop, unordered-containers, text, lens, double-conversion,- semigroups, bytestring, containers, monad-supply,+ semigroups, bytestring >= 0.10.8.0, containers, monad-supply, template-haskell, transformers, exceptions, amazonka, monad-loops, conduit, hashable, amazonka-core, aeson, vector, scientific,- tagged+ tagged, uuid-types -- hspec, safe-exceptions hs-source-dirs: src default-language: Haskell2010
src/Database/DynamoDB.hs view
@@ -49,6 +49,7 @@ , queryCond , querySource , querySourceChunks+ , querySourceByKey , queryOverIndex -- * Scan options , ScanOpts
src/Database/DynamoDB/Class.hs view
@@ -27,7 +27,7 @@ DynamoCollection(..) , DynamoTable(..) , DynamoIndex(..)- , dScan+ , defaultScan , RangeType(..) , TableType(..) , gsDecode@@ -161,16 +161,13 @@ -- | Return table name and index name qsTableName :: Proxy a -> T.Text qsIndexName :: Proxy a -> Maybe T.Text- dScan :: Proxy a -> D.Scan instance (DynamoCollection a r 'IsTable, DynamoTable a r) => TableScan a r 'IsTable where qsTableName = tableName qsIndexName _ = Nothing- dScan = defaultScan instance (DynamoCollection a r 'IsIndex, DynamoIndex a parent r, DynamoTable parent r1, HasPrimaryKey a r 'IsIndex) => TableScan a r 'IsIndex where qsTableName _ = tableName (Proxy :: Proxy parent) qsIndexName = Just . indexName- dScan = defaultScan -- | Type family that returns a primary key of a table/index depending on the 'RangeType' parameter. type PrimaryKey a r = PrimaryKey' (Code a) r
src/Database/DynamoDB/Migration.hs view
@@ -243,6 +243,7 @@ Left _ -> do logmsg Info ("Creating table: " <> prettyTableInfo tabledef) void $ send tabledef -- table doesn't exist, create a new one+ waitUntilTableActive tblname True Right rs | Just descr <- rs ^. D.drsTable -> do logmsg Info ("Table " <> tblname <> " alread exists, checking schema.")
src/Database/DynamoDB/QueryRequest.hs view
@@ -21,6 +21,7 @@ , querySource , querySourceChunks , queryOverIndex+ , querySourceByKey -- * Scan , scan , scanCond@@ -40,8 +41,7 @@ ) where -import Control.Arrow (first)-import Control.Arrow (second)+import Control.Arrow (first, second) import Control.Lens (Lens', sequenceOf, view, (%~), (.~), (^.), _2) import Control.Lens.TH (makeLenses)@@ -68,6 +68,7 @@ import qualified Network.AWS.DynamoDB.Types as D import Network.AWS.Pager (AWSPager (..)) import Numeric.Natural (Natural)+import qualified Data.HashMap.Strict as HMap import Database.DynamoDB.BatchRequest (getItemBatch) import Database.DynamoDB.Class@@ -152,13 +153,32 @@ => Proxy a -> QueryOpts a hash range -> Source m [a] querySourceChunks _ q = paginate (FixedQuery (queryCmd q)) =$= CL.mapM (\res -> mapM rsDecoder (res ^. D.qrsItems)) - -- | Generic query function. You can query table or indexes that have -- a range key defined. The filter condition cannot access the hash and range keys. querySource :: forall a t m hash range. (CanQuery a t hash range, MonadAWS m) => Proxy a -> QueryOpts a hash range -> Source m a querySource p q = querySourceChunks p q =$= CL.concat ++querySourceChunksByKey :: forall a parent hash rest v1 m r.+ (DynamoIndex a parent 'NoRange, Code a ~ '[ hash ': rest ], DynamoScalar v1 hash, MonadAWS m,+ DynamoTable parent r)+ => Proxy a -> hash -> Source m [a]+querySourceChunksByKey p key = paginate (FixedQuery sQuery) =$= CL.mapM (\res -> mapM rsDecoder (res ^. D.qrsItems))+ where+ sQuery = D.query (tableName (Proxy :: Proxy parent))+ & D.qKeyConditionExpression .~ Just "#K = :key"+ & D.qExpressionAttributeNames .~ HMap.singleton "#K" (head (allFieldNames p))+ & D.qExpressionAttributeValues .~ HMap.singleton ":key" (dScalarEncode key)+ & D.qIndexName .~ (Just $ indexName p)++-- | Conduit to query global indexes with no range key; in case anyone needed it+querySourceByKey :: forall a parent hash rest v1 m r.+ (DynamoIndex a parent 'NoRange, Code a ~ '[ hash ': rest ], DynamoScalar v1 hash, MonadAWS m,+ DynamoTable parent r)+ => Proxy a -> hash -> Source m a+querySourceByKey p q = querySourceChunksByKey p q =$= CL.concat+ -- | Query an index, fetch primary key from the result and immediately read -- full items from the main table. --@@ -310,7 +330,7 @@ -- | Generate a "D.Query" object. scanCmd :: forall a r t. TableScan a r t => ScanOpts a r -> D.Scan scanCmd q =- dScan (Proxy :: Proxy a)+ defaultScan (Proxy :: Proxy a) & D.sConsistentRead . consistencyL .~ (q ^. sConsistentRead) & D.sLimit .~ (q ^. sLimit) & addStartKey (q ^. sStartKey)
src/Database/DynamoDB/Types.hs view
@@ -46,6 +46,8 @@ import qualified Data.HashMap.Strict as HMap import Data.Maybe (mapMaybe) import Data.Proxy+import Data.UUID.Types (UUID)+import qualified Data.UUID.Types as UUID import Data.Scientific (Scientific, floatingOrInteger, fromFloatDigits, toBoundedInteger, toRealFloat)@@ -114,11 +116,11 @@ class ScalarAuto v => DynamoScalar (v :: D.ScalarAttributeType) a | a -> v where -- | Scalars must have total encoding function scalarEncode :: a -> ScalarValue v- default scalarEncode :: (Show a, Read a) => a -> ScalarValue 'D.S+ default scalarEncode :: (Show a, Read a, v ~ 'D.S) => a -> ScalarValue v scalarEncode = ScS . T.pack . show scalarDecode :: ScalarValue v -> Maybe a- default scalarDecode :: (Show a, Read a) => ScalarValue 'D.S -> Maybe a+ default scalarDecode :: (Show a, Read a, v ~ 'D.S) => ScalarValue v -> Maybe a scalarDecode (ScS txt) = readMaybe (T.unpack txt) instance DynamoScalar 'D.N Integer where@@ -240,6 +242,14 @@ dDecode Nothing = Just "" dIsMissing "" = True dIsMissing _ = False+++instance DynamoEncodable UUID where+ dEncode uuid = dEncode (UUID.toText uuid)+ dDecode attr = attr >>= dDecode . Just >>= UUID.fromText+instance DynamoScalar 'D.S UUID where+ scalarEncode = ScS . UUID.toText+ scalarDecode (ScS txt) = UUID.fromText txt -- | 'Maybe' ('Maybe' a) will not work well; it will 'join' the value in the database. instance DynamoEncodable a => DynamoEncodable (Maybe a) where
test/BaseSpec.hs view
@@ -42,8 +42,13 @@ , iInt :: Int , iMText :: Maybe T.Text } deriving (Show, Eq, Ord)-mkTableDefs "migrateTest" (tableConfig "" (''Test, WithRange) [] []) +data TestKeyOnly = TestKeyOnly {+ d_iText :: T.Text+ , d_iHashKey :: T.Text+}+mkTableDefs "migrateTest" (tableConfig "" (''Test, WithRange) [(''TestKeyOnly, NoRange)] [])+ data TestSecond = TestSecond { tHashKey :: T.Text , tInt :: Int@@ -158,6 +163,13 @@ putItemBatch newItems (items :: [Test]) <- queryCond tTest "hashkey" Nothing (iInt' >. 50) Backward (-1) liftIO $ items `shouldBe` []+ withDb "querySourceByKey works/compiles correctly" $ do+ let template i = Test "hashkey" i "text" False 3.14 i Nothing+ newItems = map template [1..55]+ putItemBatch newItems+ res <- runConduit $ querySourceByKey iTestKeyOnly "text" =$= CL.consume+ liftIO $ length res `shouldBe` 55+ withDb "updateItemByKey works" $ do let testitem1 = Test "1" 2 "text" False 3.14 2 (Just "something") putItem testitem1@@ -227,7 +239,6 @@ =$= leftJoin Strongly tTestSecond iMText =$= CL.concat =$= CL.consume liftIO $ res2 `shouldBe` [(testitem1, Nothing), (testitem2, Just testsecond)]- main :: IO () main = hspec spec