I want to create a table where one of the columns is a list of Int. For example:
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
PersonTest
name String
listi [Int]
UniquePerson name
deriving Show Eq Ord
|]
Then I want to use upsert to insert a new person if it is not there yet, otherwise I want to update the list to include the int numbers in the new record. I wrote this small test:
test_experiment :: IO ()
test_experiment = do
let p1 = [PersonTest "Dan" [1,2]
,PersonTest "Jo" []
,PersonTest "Dan" [4]] -- This triggers an update
upse = (\pl -> runSqlite "dbe.sqlite" $ do
runMigration migrateAll
mapM_ (\p -> upsert p [PersonTestListi +=. p.personTestListi]) pl )
upse p1
When I run this I get the runtime error:
PersistMarshalError "getBy: Couldn't parse field listi
from table person_test
. Failed to parse Haskell type List
; expected list, string, bytestring or null from database, but received: PersistByteString "0". Potential solution: Check that your database schema matches your Persistent model definitions."
What am I doing wrong? I was under the impression that this was supported?
Are there workarounds?
I want to create a table where one of the columns is a list of Int. For example:
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
PersonTest
name String
listi [Int]
UniquePerson name
deriving Show Eq Ord
|]
Then I want to use upsert to insert a new person if it is not there yet, otherwise I want to update the list to include the int numbers in the new record. I wrote this small test:
test_experiment :: IO ()
test_experiment = do
let p1 = [PersonTest "Dan" [1,2]
,PersonTest "Jo" []
,PersonTest "Dan" [4]] -- This triggers an update
upse = (\pl -> runSqlite "dbe.sqlite" $ do
runMigration migrateAll
mapM_ (\p -> upsert p [PersonTestListi +=. p.personTestListi]) pl )
upse p1
When I run this I get the runtime error:
PersistMarshalError "getBy: Couldn't parse field listi
from table person_test
. Failed to parse Haskell type List
; expected list, string, bytestring or null from database, but received: PersistByteString "0". Potential solution: Check that your database schema matches your Persistent model definitions."
What am I doing wrong? I was under the impression that this was supported?
Are there workarounds?
Share Improve this question edited Feb 14 at 19:41 user3716072 asked Feb 14 at 16:31 user3716072user3716072 1971 gold badge4 silver badges15 bronze badges 2- Dumb question, but the message describes a migration. Are you actually doing a migration? If so, are you sure the problem is with the upsert, and not with the migration? – Daniel Wagner Commented Feb 14 at 19:21
- 1 Not doing a migration. That is just the output of the test harness when it creates the DataBase from scratch. I think it is an issue with upsert, if you remove the third entry in p1 then the database is created successfully. – user3716072 Commented Feb 14 at 19:41
1 Answer
Reset to default 0Sqlite doesn't support arrays, that's why you see that error message. I confirmed that this works without an array:
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.IO.Class (liftIO)
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
PersonTest
name String
listi Int
UniquePerson name
deriving Show Eq Ord
|]
main :: IO ()
main = runSqlite ":memory:" $ do
runMigration migrateAll
let p1 = [PersonTest "Dan" 1
,PersonTest "Jo" 2
,PersonTest "Dan" 3
]
mapM_ (\p -> upsert p [PersonTestListi +=. (personTestListi p)]) p1
persons :: [Entity PersonTest] <- selectList [] []
liftIO $ print persons
One way to solve this issue would be to use JSON's serialization using Aeson support in persistent.