我对Yesod完全不熟悉(并且在haskell方面不是很有经验)而且我正在尝试构建我的第一个处理程序。我使用默认参数(我使用Yesod 0.9.4.1版本并在scraffolding中选择postgresql)对我的应用进行了诈骗,现在我正在尝试使用selectList从表中检索一些数据。我在模型配置文件中定义了一个新表(让我们称之为Foo):
Foo
xStart Int
yStart Int
并希望传递FooId和其他一些Foo属性的列表,因此我定义了一条路线:
/foos/#Int/#Int/*FooId FoosReturnR GET
和一个处理程序:
module Handler.FoosReturn where
import Import
selectWindowSize :: Int
selectWindowSize = 10000
getFoosReturnR :: Int -> Int -> [FooId] -> Handler RepPlain
getFoosReturnR x y withoutIds = do
foos <- runDB $ selectList [FooId /<-. withoutIds,
FooXStart <. x + selectWindowSize,
FooXStart >=. x - selectWindowSize,
FooYStart <. y + selectWindowSize,
FooYStart >=. y - selectWindowSize] []
return $ RepPlain $ toContent $ show foos
我在Application.hs中导入了处理程序并将其添加到cabal文件中,现在当我尝试运行它时,我收到一条错误,说FooId不是MultiPiece的实例 - 但是当我尝试将它作为实例时有一个错误说FooId是一个类型的同义词,不能是MultiPiece的一个实例 - 如何解决这个问题?
编辑: 丹尼尔:嗯,实际上我不知道FooId究竟是什么 - 它是Yesod魔法的一部分,到目前为止我还不完全理解 - 它是从表定义中自动生成的 - 但它是某种数字。
因为我不知道如何使用MultiPiece,我改用了更简单的解决方案并进行了修改:
路线:/foos/#Int/#Int/#String FoosReturnR GET
处理程序:[还添加了一些日志记录]
module Handler.FoosReturn where
import Import
import Data.List.Split
import qualified Data.Text.Lazy as TL
selectWindowSize :: Int
selectWindowSize = 10000
getFoosReturnR :: Int -> Int -> String -> Handler RepPlain
getFoosReturnR x y withoutIds = do
app <- getYesod
liftIO $ logLazyText (getLogger app) ("getFoosReturnR('" `TL.append` (TL.pack $ (show x) ++ "', '" ++ (show y) ++ "', '" ++ withoutIds ++ "') "))
foos <- runDB $ selectList [FooId /<-. (map (\a -> read a :: FooId) $ splitOn "," withoutIds),
FooXStart <. x + selectWindowSize,
FooXStart >=. x - selectWindowSize,
FooYStart <. y + selectWindowSize,
FooYStart >=. y - selectWindowSize] []
return $ RepPlain $ toContent $ show foos
现在它正在编译但是当我浏览到:http://localhost:3000/sectors/1/1/1,2时,我得到的页面只包含: 内部服务器错误 Prelude.read:没有解析
好吧,我不完全明白这里的FooId是什么 - 如何从包含数字的字符串列表中创建这样的FooId列表?
当然,最需要一个如何使FooId成为MultiPiece实例的解决方案。
编辑:
Daniel和svachalek,感谢您的帖子 - 我尝试了您的(Daniel's)解决方案,但后来我收到错误,说[FooId]是预期的(如处理函数声明中)但是给出了FooId类型,这导致我以下解决方案:
data FooIds = FooIds [FooId] deriving (Show, Read, Eq)
instance MultiPiece FooIds where
toMultiPiece (FooIds fooList) = map (Data.Text.pack . show) fooList
fromMultiPiece texts =
if length (filter isNothing listOfMaybeFooId) > 0
then Nothing
else Just $ FooIds $ map fromJust listOfMaybeFooId
where
listOfMaybeFooId = map constructMaybeFooId texts
constructMaybeFooId :: Text -> Maybe FooId
constructMaybeFooId x = case reads (Data.Text.unpack x) :: [(FooId,String)] of
[(foo,_)] -> Just foo
_ -> Nothing
当然我改变了路线:/foos/#Int/#Int/*FooIds FoosReturnR GET
和处理程序:
getFoosReturnR :: Int -> Int -> FooIds -> Handler RepPlain
getFoosReturnR coordX coordY (FooIds withoutIds) = do
现在我在编译和运行时都没有出现任何错误,唯一不满意的是我总是收到Not Found的结果,即使我提供的参数可以给我一些结果 - 所以现在我有了找出如何确定哪些SQL确切地发送到数据库
编辑:
现在我看到“Not Found”与问题相关并且上面的编辑不是解决方案 - 当我浏览到localhost:3000 / foos / 4930000/3360000然后我得到了结果(但随后是FooIds是空的) - 但是当我添加类似:localhost:3000 / sectors / 4930000/3360000/1之类的东西时,我总是得到“Not Found” - 所以它仍然没有工作..
答案 0 :(得分:1)
希望我能提供帮助,但据我所知,yesod与网络应用程序有关,因此我从未真正看过它。所以我可以尝试在空中刺,也许我会碰到一些东西。
Hayoo导致
class MultiPiece s where
fromMultiPiece :: [Text] -> Maybe s
toMultiPiece :: s -> [Text]
Yesod.Dispatch
中的。由于FooId
似乎有Read
个实例,可能还有Show
个实例,您可以尝试
{-# LANGUAGE TypeSynonymInstances #-}
-- maybe also FlexibleInstances
instance MultiPiece FooId where
toMultiPiece foo = [Text.pack $ show foo]
fromMultiPiece texts =
case reads (unpack $ Text.concat texts) :: [(FooId,String)] of
[(foo,_)] -> Just foo
_ -> Nothing
我不知道这是否接近正确的事情,我会把它作为评论发布,但它太长了,评论中没有太多的格式。如果它没有帮助,我会将其删除,以便在没有答案的情况下不再给出问题。
答案 1 :(得分:1)
问题解决了:))
您可以使用问题的最后一次修改中的我的实现,并浏览到以下网址:http://localhost:3000/foos/4930000/3360000/Key {unKey = PersistInt64 3}/Key {unKey = PersistInt64 4}
Key类型派生Read但不是以非常友好(和预期)的方式:)
或者将fromMultiPiece的实现更改为:
instance MultiPiece FooIds where
toMultiPiece (FooIds fooList) = map (Data.Text.pack . show) fooList
fromMultiPiece texts =
if length (filter isNothing listOfMaybeFooId) > 0
then Nothing
else Just $ FooIds $ map fromJust listOfMaybeFooId
where
listOfMaybeFooId = map constructMaybeFooId texts
constructMaybeFooId :: Text -> Maybe FooId
constructMaybeFooId x = case TR.decimal x of
Left err -> Nothing
Right (el,_) -> Just $ Key (PersistInt64 el)
并使用以下网址:http://localhost:3000/foos/4930000/3360000/1/2
非常感谢Yesod Web Framework Google Group的David McBride
fromPersistValue
和toPersistValue
函数进行修复来自Database.Persist
如下:
instance MultiPiece FooIds where
toMultiPiece (FooIds fooList) = map (persistValuetoText . unKey) fooList
where
persistValuetoText x = case fromPersistValue x of
Left _ -> Data.Text.pack ""
Right val -> Data.Text.pack $ show (val::Int)
fromMultiPiece texts =
if length (filter isNothing listOfMaybeFooId) > 0
then Nothing
else Just $ FooIds $ map fromJust listOfMaybeFooId
where
listOfMaybeFooId = map constructMaybeFooId texts
constructMaybeFooId :: Text -> Maybe FooId
constructMaybeFooId x = case TR.decimal x of
Left _ -> Nothing
Right (el,_) -> Just $ Key (toPersistValue (el :: Int))
再次,非常感谢David McBride也为此付出了代价!
答案 2 :(得分:0)
我也是Yesod的新手,我放弃并将-XTypeSynonymInstances添加到我的.cabal文件中的ghc-options中,到目前为止,它让我的生活变得更轻松。我不确定它是否是这个特定问题的最优雅答案,但我预测你会经常遇到该别名实例错误。附:尝试id =(Key(PersistInt 64 n))