yesodweb / persistent

Persistence interface for Haskell allowing multiple storage methods.
MIT License
467 stars 296 forks source link

[Feature request] Support custom FromJSON and ToJSON for entity keys? #795

Open ryota-ka opened 6 years ago

ryota-ka commented 6 years ago

Hello.

I use Yesod + Persistent to build my application, and I'm planning to use hashids for primary key representations, since I've thought it would be nice if the traditional integer ids would be hidden from users.

I also tried to make entity keys (such as Key User) an instance of FromJSON and ToJSON, which encodes to / decodes from hashid representations (i.e. String constructor of aeson's Value type), but I realized that Database.Persist.TH made them instances of FromJSON and ToJSON type, whose values are treated as Number.

I read the haddock document, but I couldn't find the way to provide custom instance declaration for them. (I've found mpsEntityJSON, which allow us to work with Entity a, but what I've wanted is the one for Key a.)

Thanks.

MaxGabriel commented 6 years ago

You can specify your own type to use for the primary key like in this example using UUIDs:

Id UUID default=uuid_generate_v1mc

What about just creating a newtype over Int64 as your primary key type, and giving it the custom to json instance?

ryota-ka commented 6 years ago

Thank you for your reply.

What about just creating a newtype over Int64 as your primary key type, and giving it the custom to json instance?

Yes, that's surely what I (unwillingly) trying to do. However, I believe that my suggestion is not so bad, as I suppose as below.

The current implementation does not allow us to customize the behavior, nor to prohibit becoming an instance. It involves the risk where a careless programmer makes a mistake, say, UserId for its newtype, and this may result in the situation where an end user observes an undesirable output.

Int64 values (or any other database-dependent ones) obviously derive from database implementation, and I believe there are some circumstances where we wish to treat them as mere internal representation, and abstract them away from application logic.

MaxGabriel commented 6 years ago

Ok fair enough, I think it's worth having. Is this something you'd be interested in contributing?

ryota-ka commented 6 years ago

Yes, of course I’m interested in it. Then I’ll try to send a pull request. Thanks!

ryota-ka commented 6 years ago

I attempted to define the default implementations for keyToJSON in Database.Persist.Class.PersistEntity, which extracts the internal value and utilize its toJSON method, but I couldn't find deconstruct a Key value polymorphically. As key constructors (and even unFooKey functions) are defined using TH independently each other, it seems that we have no means to treat them comprehensively.

I'd like you to ask you for your help if you have any good idea.