-- Copyright 2020 Fernando Rincon Martin
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-------------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ImpredicativeTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE RecordWildCards #-}
module Logic where
import Prelude hiding (id)
import Data.Aeson
import Data.IORef (IORef, readIORef, newIORef, atomicModifyIORef')
import Data.List (find)
import Data.Maybe (fromMaybe)
import Data.Text (Text)
import GHC.Generics
type Context = IORef [Pet]
data Pet =
Pet
{ id :: Int
, name :: Text
, tag :: Text
} deriving (Generic, Show)
instance ToJSON Pet
instance FromJSON Pet
data OffsetPagination =
OffsetPagination
{ limit :: Maybe Int
, page :: Maybe Int
}
data ListResult a = ListResult
{ resultList :: [a]
, page :: Int
, totalPages :: Int
, itemsPerPage :: Int
, itemsTotal :: Int
}
-- Model/DAO Methods
initialContext :: IO (IORef [Pet])
initialContext = newIORef
[ Pet 1 "scooby" "no-tag"
, Pet 2 "canelo" "dog"
]
defaultLimit :: Int
defaultLimit = 10
listPets :: Context -> OffsetPagination -> IO (ListResult Pet)
listPets context OffsetPagination{..} = do
let actualLimit = fromMaybe defaultLimit limit
let actualPage = fromMaybe 1 page
pets <- readIORef context
return ListResult
{ resultList = take actualLimit $ drop ((actualPage - 1) * actualLimit) pets
, page = actualPage
, totalPages = ((length pets) `div` actualLimit) + if (length pets) `mod` actualLimit == 0 then 0 else 1
, itemsPerPage = actualLimit
, itemsTotal = length pets
}
getPet :: Context -> Int -> IO (Maybe Pet)
getPet context petId = do
pets <- readIORef context
return $ find (\pet -> id pet == petId) pets
createOrReplacePet :: Context -> Pet -> IO Bool
createOrReplacePet context newPet = atomicModifyIORef' context doIt
where
doIt pets =
( newPet:(filter (\pet -> id pet /= id newPet) pets)
, all (\pet -> id pet /= id newPet) pets
)