Скотти параметры для подачи в Sqlite3

Я пытаюсь создать веб-сайт, который будет получать информацию по URL-маршрутам, а затем передавать эту информацию в HDBC SQLITE3 база данных. Я выяснил, как получить информацию через параметры, используя Скотти, а также как создать базу данных, используя HDBC. Но у меня возникают проблемы при передаче информации о параметрах в базу данных. Я получаю эту ошибку: (извините за такую ​​проблему новичка, я использую Haskell только около трех недель)

Controllers/Home.hs:51:48:
No instance for (Convertible a0 SqlValue)
  arising from a use of `toSql'
Possible fix:
  add an instance declaration for (Convertible a0 SqlValue)
In the expression: toSql
In the expression: toSql $ userId
In the third argument of `run', namely
  `[toSql $ userId, toSql $ name]'

Controllers/Home.hs:51:64:
No instance for (Convertible a1 SqlValue)
  arising from a use of `toSql'
Possible fix:
  add an instance declaration for (Convertible a1 SqlValue)
In the expression: toSql
In the expression: toSql $ name
In the third argument of `run', namely
  `[toSql $ userId, toSql $ name]'

Вот код, который я пытаюсь запустить:

import Control.Monad
import Web.Scotty (ScottyM, ActionM, get, html, param)
import Data.Monoid (mconcat)
import Database.HDBC
import Database.HDBC.Sqlite3
import Control.Monad.Trans ( MonadIO(liftIO) )
import Data.Convertible
createUser ::  ScottyM()
createUser = get "/create/user/:userId/:name" $ do
  name <- param "name"
  userId <- param "userId"
  liftIO $ createUserDB name userId
  html $ mconcat ["<p>/create/user/" , userId , "/" , name ,"</p>"]
createUserDB :: a1 -> a0 -> IO()
createUserDB name userId = do
  conn <- connectSqlite3 databaseFilePath
  run conn "INSERT INTO users VALUES (? , ?)" [toSql $ userId, toSql $ name]
  commit conn
  disconnect conn
databaseFilePath = "data/mydb.db"

Если бы кто-то мог предоставить, как это исправить, а также почему его исправление работает, это было бы очень полезно!

1 ответ

Решение

Я думаю, что компилятор жалуется, потому что код требует, чтобы аргументы createUserDB удовлетворить ограничение в сообщении об ошибке (то есть, что они могут быть преобразованы в Sqlvalue), но подпись, которую вы дали, не дает такой гарантии (a0 а также a1 может быть любого типа).

Самый простой вариант - удалить сигнатуру типа для createUserDB и просто дайте компилятору сделать вывод. В качестве альтернативы вы можете ограничить его Text значения (с name а также userId имеют тип Text а также Database.HDBC.SqlValue определяет экземпляр для Convertible Text SqlValue):

createUserDB :: Text -> Text -> IO ()

В общем, вы также можете использовать контекст в сигнатуре функции для ограничения типов:

createUserDB :: (Convertible a0 SqlValue, Convertible a1 SqlValue) => a1 -> a0 -> IO ()

но это, вероятно, не очень хорошая идея, когда типы явно являются строками SQL и, вероятно, сопоставлены с varchars.

Другие вопросы по тегам