json-api-lib 0.1.0.0 → 0.1.1.0
raw patch · 5 files changed
+98/−20 lines, 5 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
+ Network.JSONApi: PageNum :: Int -> PageNum
+ Network.JSONApi: PageSize :: Int -> PageSize
+ Network.JSONApi: ResourceCount :: Int -> ResourceCount
+ Network.JSONApi: [getPageNum] :: PageNum -> Int
+ Network.JSONApi: [getPageSize] :: PageSize -> Int
+ Network.JSONApi: [getResourceCount] :: ResourceCount -> Int
+ Network.JSONApi: newtype PageNum
+ Network.JSONApi: newtype PageSize
+ Network.JSONApi: newtype ResourceCount
+ Network.JSONApi.Resource: PageNum :: Int -> PageNum
+ Network.JSONApi.Resource: PageSize :: Int -> PageSize
+ Network.JSONApi.Resource: ResourceCount :: Int -> ResourceCount
+ Network.JSONApi.Resource: [getPageNum] :: PageNum -> Int
+ Network.JSONApi.Resource: [getPageSize] :: PageSize -> Int
+ Network.JSONApi.Resource: [getResourceCount] :: ResourceCount -> Int
+ Network.JSONApi.Resource: instance GHC.Show.Show Network.JSONApi.Resource.PageNum
+ Network.JSONApi.Resource: instance GHC.Show.Show Network.JSONApi.Resource.PageSize
+ Network.JSONApi.Resource: instance GHC.Show.Show Network.JSONApi.Resource.ResourceCount
+ Network.JSONApi.Resource: newtype PageNum
+ Network.JSONApi.Resource: newtype PageSize
+ Network.JSONApi.Resource: newtype ResourceCount
- Network.JSONApi: indexLinks :: ResourcefulEntity e => e -> Maybe Int -> Maybe Int -> Maybe Int -> Links
+ Network.JSONApi: indexLinks :: ResourcefulEntity e => e -> Maybe Text -> PageSize -> PageNum -> ResourceCount -> Links
- Network.JSONApi.Resource: indexLinks :: ResourcefulEntity e => e -> Maybe Int -> Maybe Int -> Maybe Int -> Links
+ Network.JSONApi.Resource: indexLinks :: ResourcefulEntity e => e -> Maybe Text -> PageSize -> PageNum -> ResourceCount -> Links
Files
- json-api-lib.cabal +1/−1
- src/Network/JSONApi.hs +3/−0
- src/Network/JSONApi/Document.hs +0/−4
- src/Network/JSONApi/Resource.hs +33/−14
- test/Network/JSONApi/ResourceSpec.hs +61/−1
json-api-lib.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.0 name: json-api-lib-version: 0.1.0.0+version: 0.1.1.0 homepage: https://github.com/shirren/json-api-lib bug-reports: https://github.com/shirren/json-api-lib/issues license: MIT
src/Network/JSONApi.hs view
@@ -7,8 +7,11 @@ , D.ErrorDocument (..) , D.Included , E.Error (..)+, R.PageNum (..)+, R.PageSize (..) , R.Relationship , R.Resource (..)+, R.ResourceCount (..) , R.Relationships , R.ResourcefulEntity (..) , I.HasIdentifier (..)
src/Network/JSONApi/Document.hs view
@@ -84,10 +84,6 @@ newtype Included = Included [Value] deriving (Show) --- instance Monoid Included where--- mempty = Included []--- mappend (Included as) (Included bs) = Included (as <> bs)- {- | Constructor function for the Document data type.
src/Network/JSONApi/Resource.hs view
@@ -4,7 +4,10 @@ Specification: <http://jsonapi.org/format/#document-resource-objects> -} module Network.JSONApi.Resource-( Resource (..)+( PageNum (..)+, PageSize (..)+, Resource (..)+, ResourceCount (..) , Relationships , ResourcefulEntity (..) , Relationship@@ -20,8 +23,8 @@ import qualified Data.Aeson as AE import Data.Aeson.Types (fieldLabelModifier) import Data.Map (Map)-import Data.Maybe (fromMaybe) import qualified Data.Map as Map+import Data.Maybe (fromMaybe) import Data.Text (Text, pack) import GHC.Generics hiding (Meta)@@ -142,25 +145,41 @@ Helper function to build relative links for a single resource of type ResourceEntity -} showLink :: ResourcefulEntity e => e -> Links-showLink resource = mkLinks [ ("self", selfLink) ]+showLink resource = mkLinks [ ("self", buildLink) ] where- selfLink = "/" <> resourceType resource <> "/" <> resourceIdentifier resource+ buildLink = "/" <> resourceType resource <> "/" <> resourceIdentifier resource {- |+We can specify limits on the number of rows we would like back from the database+-}+newtype PageSize = PageSize {+ getPageSize :: Int+} deriving Show++newtype PageNum = PageNum {+ getPageNum :: Int+} deriving Show++newtype ResourceCount = ResourceCount {+ getResourceCount :: Int+} deriving Show++{- | Helper function to beuild relative links for a collection of resources of type ResourceEntity. This helper function assumes that the first page is always page 0. -}-indexLinks :: ResourcefulEntity e => e -> Maybe Int -> Maybe Int -> Maybe Int -> Links-indexLinks resource mPageSize mPageNo documentCount = mkLinks [- ("self", genLink pageNo)+indexLinks :: ResourcefulEntity e => e -> Maybe Text -> PageSize -> PageNum -> ResourceCount -> Links+indexLinks resource baseUrl pageSize pageNum resourceCount = mkLinks [+ ("self", genLink pgNum) ,("first", genLink (0 :: Int))- ,("prev", genLink (if pageNo - 1 < 0 then 0 else pageNo - 1))- ,("next", genLink (pageNo + 1))- ,("last", genLink ((fromMaybe 0 documentCount `quot` pageSize) - 1 ))]+ ,("prev", genLink (if pgNum - 1 < 0 then 0 else pgNum - 1))+ ,("next", genLink (pgNum + 1))+ ,("last", genLink ((resCount `quot` pgSize) - 1))] where- pageSize = fromMaybe 10 mPageSize- pageNo = fromMaybe 0 mPageNo- genLink no = "/" <> resourceType resource <> "?" <>+ pgNum = if getPageNum pageNum < 0 then 0 else getPageNum pageNum+ pgSize = if getPageSize pageSize <= 0 then 1 else getPageSize pageSize+ resCount = if getResourceCount resourceCount < 0 then 0 else getResourceCount resourceCount+ genLink no = fromMaybe "" baseUrl <> "/" <> resourceType resource <> "?" <> encodeText "page[number]" <> "=" <> (pack . show) no <>- "&" <> encodeText "page[size]" <> "=" <> (pack . show) pageSize+ "&" <> encodeText "page[size]" <> "=" <> (pack . show) pgSize
test/Network/JSONApi/ResourceSpec.hs view
@@ -16,12 +16,72 @@ main = hspec spec spec :: Spec-spec =+spec = do describe "JSON serialization" $ it "can be encoded and decoded from JSON" $ do let encodedJson = BS.unpack . prettyEncode $ toResource testObject let decodedJson = AE.decode (BS.pack encodedJson) :: Maybe (Resource TestObject) isJust decodedJson `shouldBe` True++ describe "Self links" $+ it "can be constructed for a single high level resource" $ do+ let links = showLink testObject+ links `shouldBe` mkLinks [ ("self", "/TestObject/1") ]++ describe "Index links" $ do+ it "should always start at page 0" $ do+ let links = indexLinks testObject Nothing (PageSize 10) (PageNum 1) (ResourceCount 20)+ links `shouldBe` mkLinks [+ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10")+ , ("last","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10")+ , ("next","/TestObject?page%5Bnumber%5D=2&page%5Bsize%5D=10")+ , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10")+ , ("self","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10")]++ it "should never have a negative prev page" $ do+ let links = indexLinks testObject Nothing (PageSize 10) (PageNum 0) (ResourceCount 20)+ links `shouldBe` mkLinks [+ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10")+ , ("last","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10")+ , ("next","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10")+ , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10")+ , ("self","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10")]++ it "should handle a page size of 0" $ do+ let links = indexLinks testObject Nothing (PageSize 0) (PageNum 0) (ResourceCount 2)+ links `shouldBe` mkLinks [+ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")+ , ("last","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1")+ , ("next","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1")+ , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")+ , ("self","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")]++ it "should handle a negative page num" $ do+ let links = indexLinks testObject Nothing (PageSize 0) (PageNum $ -1) (ResourceCount 2)+ links `shouldBe` mkLinks [+ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")+ , ("last","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1")+ , ("next","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1")+ , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")+ , ("self","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")]++ it "should handle a negative resource count" $ do+ let links = indexLinks testObject Nothing (PageSize 1) (PageNum 0) (ResourceCount $ -1)+ links `shouldBe` mkLinks [+ ("first","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")+ , ("last","/TestObject?page%5Bnumber%5D=-1&page%5Bsize%5D=1")+ , ("next","/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=1")+ , ("prev","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")+ , ("self","/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=1")]++ it "should handle nested resource paths" $ do+ let links = indexLinks testObject (Just "/ParentObject/1") (PageSize 10) (PageNum 1) (ResourceCount 20)+ links `shouldBe` mkLinks [+ ("first","/ParentObject/1/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10")+ , ("last","/ParentObject/1/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10")+ , ("next","/ParentObject/1/TestObject?page%5Bnumber%5D=2&page%5Bsize%5D=10")+ , ("prev","/ParentObject/1/TestObject?page%5Bnumber%5D=0&page%5Bsize%5D=10")+ , ("self","/ParentObject/1/TestObject?page%5Bnumber%5D=1&page%5Bsize%5D=10")] data TestObject = TestObject { myId :: Int