-
Notifications
You must be signed in to change notification settings - Fork 296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is anyone actually using mpsGeneric ? #1204
Comments
I'm going to throw a deprecation notice on |
As documented in #1266, I want to wait until |
The |
Stackage LTS 18.0 has Going to set a calendar reminder to do that... |
Thinking about this more - When mkPersist sqlSettings { mpsGeneric = True } [persistLowerCase|
User
name String
age Int
|]
-- ===>
type User = UserGeneric SqlBackend
data UserGeneric backend = User
{ userName :: String
, userAge :: Int
}
newtype instance Key (UserGeneric backend) = UserKey
{ unUserKey :: BackendKey backend
}
type instance PersistEntityBackend (UserGeneric backend) = backend Which lets us write: user :: UserGeneric backend
user = User { userName = "matt", userAge = 33 }
mongo :: ReaderT MongoContext IO (BackendKey MongoContext)
mongo = unUserKey <$> insert user
sql :: ReaderT SqlBackend IO (BackendKey SqlBackend)
sql = unUserKey <$> insert user The idea is that the output of But we can already share this - we have a function share [mkPersist sqlSettings, mkPersist mongoSettings] [persistLowerCase| ... |] But we have a problem - the types aren't the same, so we can't share or easily convert from Mongo representation to SQL representation. Also the generated Haskell datatypes would share the same name, so it would break. Adding a prefix/suffix to the Another option is to splice the QQ separately from the module ModelDefinition where
models :: [UnboundEntityDef]
models = [persistLowerCase| ... |]
module Models.Sql where
import ModelDefinition
mkPersist sqlSettings models
module Models.Mongo where
import ModelDefinition
mkPersist mongoSettings models For modules that perform interop, you'd need to write things qualified and do conversions manually. This works but it means that you can't write stuff that's generic on the insertUser :: UserGeneric backend -> ReaderT backend IO (Key (UserGeneric backend))
insertUser = insert User { userName = "Matt", userAge = 32 }
selectUsersWith :: ReaderT backend IO [Entity (UserGeneric backend)]
selectUsersWith =
selectList [UserAge >=. 30] [] or other functions that talk about -- simplified slightly
class PersistStore backend where
insert
:: (PersistEntity record, PersistEntityBackend record ~ backend)
=> record -> ReaderT backend IO (Key record) When we have 🤔 What if we remove the constraint? class PersistStore backend where
insert
:: (PersistEntity record)
=> record -> ReaderT backend IO (Key record) Well- we're essentially saying, "Give me a This also completely breaks 🤔 It does seem like we'd want different 🤔 It feels like my choices are:
I think 4 is the right approach. But So, we have a class for relating a type to it's backend: class PersistEntity record where
type PersistBackend record :: Type
instance PersistEntity Sql.User where
type PersistBackend Sql.User = SqlBackend
instance PersistEntity Mongo.User where
type PersistBackend Mongo.User = MongoContext If we want to make it generic, then we need to somehow introduce a target backend type in the thing. insert
:: (PersistEntity ent, PersistStoreWrite backend, PersistBackend ent ~ backend)
=> ent -> ReaderT backend IO (Key ent) A type class that injects a bit of polymorphism might work. class (PersistEntity a, PersistEntity b) => CrossDatabase a b where
crossDatabase :: a -> b
type PersistGeneric a b backend = (CrossDatabase a b, PersistBackend b ~ backend) So if I want to make a f
:: (PersistGeneric Sql.User rec backend)
=> Sql.User -> ReaderT backend IO (Key rec)
f user = insert $ crossDatabase user What uh does kind of suck here is that we can't have a functional dependency - since we'd want to generate a self instance and several potential other instances. instance CrossDatabase Sql.User Sql.User where crossDatabase = id
isntance CrossDatabase Sql.User Mongo.User where crossDatabase = ...
instance CrossDatabase Sql.User Redis.User where ...
instance CrossDatabase Mongo.User Mongo.User where ...
instance CrossDatabase Mongo.User Sql.User where ...
instance CrossDatabase Mongo.User Redis.User where ...
instance CrossDatabase Redis.User Redis.User where ...
... This ends up requiring To make UX better, you could presumably just operate on a single database as the "blessed" representation, and then only write I think - as a first step - the right thing to do here is to:
|
A problem with the above approach is that Right now, with In a non-default ID case, like:
then the generic does let me introspect on it:
But the type variables don't give me the ability to write these. I'd need to include that stuff in the class. |
Something that's striking me as a somewhat obvious fix here is to have, like: module Persistent.Test.Models where
models :: String
models = [str|
|]
module Persistent.Test.Sql where
import Persistent.Test.Models
mkPersist sqlSettings $(quoteExp persistLowerCase models)
module Persistent.Test.MongoDB where
import Persistent.Test.Models
mkPersist mongoSettings $(quoteExp persistLowerCase models) 🤔 That at least allows you to share the model definitions among the different backends, even if it doesn't let you share the tests themselves. EDIT: Oh wait, we don't even need that, we can just have |
The
mpsGeneric
flag complicatespersistent-template
considerably and has a dubious value proposition - it allows you to reuse a model in a SQL context and a Redis context and a MongoDB context.This doesn't seem very useful. Removing it would be great. But I don't want to break people who need this for some reason.
Unfortunately, I can't just, like, collect data on this. What I can do, however, is deprecate the field, and link to this issue. Folks that upgrade will see the deprecation notice and be able to common on whether they use it or not.
The text was updated successfully, but these errors were encountered: