Open gibiansky opened 9 years ago
Not supported, although I would like to. You can write a function to translate from your data type into a persistent data type.
Ok. Thanks.
Function to go back and forth is doable but somewhat of a pain for a large complex object.
Can I use derivePersistField
for this?
Yes, derivePersistField
should do the trick.
Reading a bit more, it looks like derivePersistField
uses Show
and Read
marshalling. There's no way that could support migrations, right? It seems like it shouldn't support migrations (e.g. adding a field breaks Read
) so it's not quite the same, and it's really intended for simple fields that won't change their structure.
If the data structures don't change then the migrations should be fine.
For things that could not be migrated automatically, I have written Haskell code to do the migration.
If my entire application uses derivePersistField
, I will have migrations that will need to be written. The data structures are likely to change. How would you write migrations for something that uses derivePersistField
?
Say you have a table T
with a field of type CustomData
and you want to update that field.
You now need two versions of that data type, the old CustomDataOld
and the new CustomData
and you need a function convertCustomData
which converts old to new.
Now you can then create a new table Tnew
, with the same fields as T
except with CustomDataOld
replaced with the new CustomData
. You can then read rows from T
, writing them the Tnew
converting CustomDataOld
to CustomData
along them way.
Finally you delete T
and rename Tnew
to T
.
I hope I don't need to say that you test the code you write for the above on a cloned version of the DB :-).
I guess that's possible, that that's going to be a large proliferation of data types, with every change resulting in a new data type, no matter how small the change. I don't think that is a reasonable approach, although I guess it would work. It's certainly error-prone and not scalable.
I think I will avoid using derivePersistField
. For the time being I can use something other than persistent
, as I don't like the idea of committing to persistent
and putting it at the forefront of my application. (In general I think the lack of this feature is very anti-modular: it means I cannot separate my data types and the way they are stored easily.) Hopefully this will be implemented soon!
If this is a problem, I suspect that you are designing you database schema incorrectly. Most database fields should be simple things like Text
, Int
, Bool
etc. Other enumerations like data Wibble = A | B | C
should also be fine. I would advise against using complicated data types in a database field.
That is my point: derivePersistField
is meant for fields only. I would like to have my database schema represented by records which are not defined through persistent's quasiquoters. Instead of
share [...] [persistLowerCase|
Person
name String
age Int
|]
I would like to write
data Person = Person { name :: String, age :: Int }
derivePersistent 'Person
Or something like that.
Ok, looks like you are little confused.
If you define:
share [...] [persistLowerCase|
Person
name String
age Int
|]
then persistent will automatically create accessors named personName
and personAge
.
I realize that. I don't want that behaviour, because I already have a bunch of defined records, and I don't want to have to rewrite those records in persistent
's quasiquoter.
In general, I don't want persistent
generating my data types. I want to use my existing data types with persistent
. This may just be the wrong way to use persistent
, but the majority of the tutorials don't seem to imply so.
This is also my main issue with persistent, the use of quasi-quotes. It's something I consider as a more complex Haskell feature and it may confuse less-advanced people reading my code. I really think persistent
is brilliant but I don't want to have to sacrifice readability and thus maintainability.
Is there some "right" solution for this problem?
It seems to me like it is implied to be having a type that you only use to store in your db and convert to and from what you actually use, but (as a newb) I don't understand what the issue is with trying to store the ("complex") datatypes I will be working with in my program "directly" in my db?
The "right" solution is to separate your serialization types and domain types, because what is Good and easy for your domain is probably not good and easy for serialization and vice versa.
If you want to use persistent
with pre-made datatypes, then you can write a PersistEntity
instance for that type. This isn't well documented and it's a good bit of work, but you can totally do it.
We could provide a Template Haskell function mkPersistEntity :: Name -> PersistOptions -> DecsQ
that would generate the PersistEntity
instance for you. There are some complications here - the persistent quasiquoter has many features for describing database specific details that Haskell data syntax doesn't cover.
This should be made easier by the #995 issue which will make Entity
less special.
I have a bunch of already-defined data types using standard Haskell syntax. Can I use
persistent
without converting them into quasiquoters? It seems like it should be possible, but I can't find any documentation on how to do so. I think I'd like a version ofmkPersist
that does not generate the actualdata
statements but rather just theEntityDefs
, but I'm not sure.Any suggestions?