Я совершенно новичок в Yesod (и не очень опытен в haskell), и я пытаюсь создать свой первый обработчик. Я создал свое приложение, используя параметры по умолчанию (я использую версию Yesod 0.9.4.1 и выбираю 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 Я получаю страницу, содержащую только: Internal Server Error Prelude.read: no parse
Ну, я не совсем понимаю, что такое FooId - как создать такой список FooId из списка строк, содержащих числа?
И, конечно же, наиболее востребовано решение, как сделать FooId экземпляром MultiPiece.
РЕДАКТИРОВАТЬ:
Даниэль и svachalek, спасибо за ваши сообщения - я попробовал ваше (Даниэля) решение, но затем я получил ошибки, говорящие о том, что ожидается [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 был отправлен в базу данных
РЕДАКТИРОВАТЬ:
Теперь я вижу, что «Не найдено» связано с проблемой и что указанное выше редактирование не является решением — когда я перехожу к localhost:3000/foos/4930000/3360000, я получаю результаты (но тогда FooIds пуст) - но когда я добавляю что-то вроде: localhost: 3000/sectors/4930000/3360000/1, я всегда получаю "Не найдено" - так что это все еще не работает.
TypeSynonymInstances
(также может потребоватьсяFlexibleInstances
). Что такоеFooId
синоним? - person Daniel Fischer   schedule 02.02.2012