问题
I am trying to store markdown in a field on a Persistent model with a MySQL backend. I've broken the use case down to:
models:
TestModel
content Markdown
Model.hs:
import Text.Markdown (Markdown)
import Yesod.Text.Markdown ()
....
This seems to create the correct migrations:
mysql> show columns in test_model;
+---------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| content | text | NO | | NULL | |
+---------+------------+------+-----+---------+----------------+
However when I try to retrieve data from this table, I'm presented with an exception. The example below is from a cabal repl
but the same happens when the application is running:
repl> testid <- db $ insert $ TestModel $ Markdown "# Hello world"
[Debug#SQL] INSERT INTO `test_model`(`content`) VALUES(?); [PersistText "# Hello world"]
repl> testmodel <- db $ get testid
[Debug#SQL] SELECT `content` FROM `test_model` WHERE `id`=?; [PersistInt64 2]
*** Exception: runFakeHandler issue: InternalError "get TestModelKey {unTestModelKey = SqlBackendKey {unSqlBackendKey = 2}}: field content: Not a PersistText value"
My first guess was that the value for the TestModel constructor was wrong, but the same error occurs even when creating the object using a markdownField
in a form:
testModelForm :: AForm Handler TestModel
testModelForm = TestModel
<$> areq markdownField "Content" Nothing
getTestModelR :: TestModelId -> Handler Html
getTestModelR testModelId = do
testmodel <- runDB $ get404 testModelId
....
08/Aug/2015:12:44:33 -0700 [Error#yesod-core] get TestModelKey {unTestModelKey = SqlBackendKey {unSqlBackendKey = 2}}: field content: Not a PersistText value @(yesod-core-1.4.12:Yesod.Core.Class.Yesod ./Yesod/Core/Class/Yesod.hs:577:5)
Has anybody seen this exception before and know how to handle it? The only documentation of this error I could seem to find was the source code for yesod-text-markdown
.
回答1:
This turned out to be caused by a bug in the persistent-mysql
package that's now fixed in persistent-mysql-2.3
.
Here's the root cause for those interested:
The MySQL C library (and by extension the Haskell mysql
package, which persistent-mysql
depends on) doesn't distinguish between binary and textual data at the type level. So if you saved a TEXT
value to the database, when it was looked it up by persistent it appeared to be binary data (a PersistByteString
).
I fixed this in #451 by checking the character set of the column, which the MySQL API docs recommend as the appropriate solution.
For more details, see that pull request or this issue.
Thanks for asking this question; I wouldn't have realized there was a bug otherwise.
来源:https://stackoverflow.com/questions/31898691/storing-markdown-in-a-yesod-persist-model