Scotty and persistence - type error when using insert function

97 Views Asked by At

I've got the following application:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}

module Main where

-- Scotty
import qualified Web.Scotty as S
import Network.Wai.Middleware.RequestLogger
import Network.Wai.Middleware.Static
import qualified Data.Text.Lazy as L
-- HTML rendering
import Text.Blaze.Html.Renderer.Text (renderHtml)
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A
import Control.Monad.IO.Class
-- Database
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import Control.Monad.Trans.Resource (runResourceT, ResourceT)
import Control.Monad.Logger
-- URL generation
import System.Random
import Control.Monad (replicateM)
-- JSON
import Data.Map (fromList)

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Link
    shortUrl L.Text
    URLKey shortUrl
    Primary shortUrl
    longUrl L.Text
    counter Int
    deriving Show
|]

getURL :: L.Text -> IO (Maybe (Entity Link))
getURL shortId = runSqlite "links.db" $ do
   maybeOriginal <- getBy $ URLKey shortId
   pure maybeOriginal

-- I don't know what type to give this, that's probably the problem
addURL short long = runSqlite "links.db" $ do
    insert $ Link short long

main :: IO ()
main = do
    -- Connect to db and run migration
    runSqlite "links.db" $ do runMigration migrateAll
    S.scotty 3000 $ do
        ...
        S.post "/shorten" $ do
            -- Get URL
            url <- S.param "url" :: S.ActionM L.Text
            -- Generate a random short URL
            randStr <- liftIO $ getRandStr 5
            -- Add the urls to the database
            liftIO $ addURL (L.pack randStr) url
            -- Send JSON response with ID
            S.json $ fromList [("id" :: String, randStr)]

I get the following error:

shortener> build (lib + exe)
Preprocessing library for shortener-0.1.0.0..
Building library for shortener-0.1.0.0..
Preprocessing executable 'shortener-exe' for shortener-0.1.0.0..
Building executable 'shortener-exe' for shortener-0.1.0.0..
[2 of 2] Compiling Main

/home/henry/haskell/shortener/app/Main.hs:86:5: error:
    • Couldn't match type ‘PersistEntityBackend (Int -> Link)’
                     with ‘SqlBackend’
        arising from a use of ‘insert’
    • In the first argument of ‘($)’, namely ‘insert’
      In a stmt of a 'do' block: insert $ Link short long
      In the second argument of ‘($)’, namely
        ‘do insert $ Link short long’
   |
86 |     insert $ Link short long
   |     ^^^^^^

--  While building package shortener-0.1.0.0 (scroll up to its section to see the error) using:
      /home/henry/.stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.1.0_ghc-9.0.2 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.1.0 build lib:shortener exe:shortener-exe --ghc-options " -fdiagnostics-color=always"
    Process exited with code: ExitFailure 1

I'm not sure how to resolve this type error and I haven't been able to find anything of use online. There was this answer with a similar problem, but the given type signature and several variations of it did not work.

1

There are 1 best solutions below

0
On BEST ANSWER

It turns out I forgot a field when inserting. I had

insert $ Link short long

I needed

insert $ Link short long 0

for the counter field of Link.

Unfortunately the error didn't make that at all clear.