-
Notifications
You must be signed in to change notification settings - Fork 39
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
Sharing types between frontend (ghcjs) and backend (ghc) #53
Comments
Groundhog is not tied to YAML although now it is the standard way to use it. Function The current YAML library gives nice error messages with exact position. It is a high priority when considering a parsing library. I am open to including other ways to specify dependencies - nicer Haskell for 'PersistDefinitions', JSON, etc. - as long as they share the similar names and structure which would keep translation straightforward. It would be nice if CPP in groundhog-th is not tied to ghcjs at all. Or if there were a Haskell library that does not use C bindings. Speed does not matter in this case. Do I understand correctly that the only thing that prevents you from using TH is YAML and if you get TH working you do not need to define
|
I like the sounds of @imalsogreg's second solution. The core problem here is that in a web app with GHCJS you usually will have some version of the following code structure:
The In the project I'm working on we have been using the CPP + type family solution. It works ok, but is frustrating and not an obvious solution for less experienced Haskell programmers. I think the second solution would work great if we create a separate package (maybe called groundhog-ghcjs) that has its own GHCJS-specific definition for mkPersist. The backend would depend on groundhog and groundhog-th, while the front end would depend on groundhog-ghcjs. Having the groundhog-ghcjs package eliminates the need for any GHCJS-specific code in groundhog-th. The best case scenario would be if groundhog-ghcjs exports all the modules exported by groundhog and groundhog-th so there is no need for any CPP at all! But if that's not possible I think a little CPP around module imports would be ok. |
I see... So if |
No, I think groundhog-ghcjs would export its own DefaultKey and Key so GHCJS does not need to build groundhog. It might be necessary to create one more package groundhog-types that defines anything used by both groundhog-th and groundhog-ghcjs (and maybe groundhog). After a brief look it seems like groundhog-types would contain CodegenConfig, PersistDefinitions, and maybe a few things from groundhog that would be common to both. |
Groundhog-ghcjs would be quite a heavyweight solution to this problem. I would prefer to keep the packages as is with perhaps some CPP. |
The comment about the DefaultKey above was referring to the current state. |
Yes, this does sound a bit heavy. But I think it would create a fantastic user experience. We've used this pattern before back when we were using haste. We ended up creating a string-compat package that allowed haste code to use backend code by exporting its own version of text and bytestring (https://github.com/Soostone/string-compat/blob/master/string-compat.cabal). |
So here is another solution, as long as we are just brainstorming: any user who wants their type to be compiled by ghcjs should avoid |
@imalsogreg Doesn't that just shift the problem from DefaultKey to Key? |
@imalsogreg Yes, it is totally possible. It will be less flexible and more verbose though. In an email @mightybyte showed a snippet #ifdef GHCJS I think that we can avoid defining instances for each datatype with #ifdef GHCJS |
Though not every key is Int64. You can have a unique key with string or even a composite key. |
Yeah, that might work. The reason we used the type family was just because that matched most closely with what groundhog was doing. |
I just threw together something that might pass for a minimal compatibility package. What do you think? |
Thank you. It is somewhat hacky but if it solves the problem it's great. |
I don't know yet how well it will work. We'll try it in some real projects and see... This solution should be good when all your keys are Int64. If you have different key types, then we would need to expand the library with a version of mkPersist that properly figures out what type to use. |
The solution here is that the user would put CPP in their cabal file to conditionally bring in |
You don't even need to do anything conditionally in the cabal file. The frontend cabal file just depends on I can certainly change the package name. Maybe something like groundhog-ghcjs-shim? |
Ah, ok. For a use case like ours I see that would work. Only if you wanted to put the |
Does ghcjs often require shims? If a datatype has Text, ByteString or JSON Value there may be some C involved too. |
Would we still need groundhog-ghcjs if groundhog-th does not have C library dependency? |
I think that if it did not have a C dependency (or if there were appropriate C shims in the ghcjs shims library), it would be fine. I would prefer to use code that's as similar as possible between ghc and ghcjs, personally. |
Yep, exactly. ghcjs comes with its own |
Can we avoid groundhog-ghcjs and have a YAML shim? |
@lykahb Correct - the c yaml parser is the only place where |
It would make sense to put the ghcjs yaml shim in the haskell |
Right, groundhog-th does not use C directly. You can open a ticket at https://github.com/snoyberg/yaml/ |
Just stumbled across this issue while struggling with a similar problem. I have my model defined in one library that gets imported by two other projects: and ghcjs-compiled client and a ghc-compiled server. But I don't really want the client to incur a groundhog dependency at all. I'm doing to little bit of manual marshaling of auto-increment primary keys to make this possible, which I don't mind, but there is no way to get foreign keys to work. It would be nice if I could do something like this:
And the |
@andrewthad |
@andrewthad |
There's now a pure haskell yaml parser: http://hackage.haskell.org/package/HsYAML-0.1.0.0 |
Groundhog's encoding of foreign keys makes relationships between tables typesafe; the price to pay is yaml parsing (which depends on a c library), code generation with template haskell, and injecting groundhog-specific type constructors (i.e.
DefaultKey
) into the user's types.This makes it hard to a library of application types with few dependencies - something we like to do if we want to share types between backend server compiled by ghc and frontend application compiled by ghcjs.
@mightybyte and I have been comparing solutions to this problem - I wonder if you have your own ideas of how to fix this?
CPP + custom type family in ghcjs case
In user code, chop out
mkPersist ghCodegen [groundhog| ... |]
from the code with CPP when the compiler is GHCJS, and instead includetype instance DefaultKey MyType = Int64
. Somewhere at the top-level definetype family DefaultKey a :: *
This works well, but is a bit of a burden on user's code.Parse YAML description in ghcjs
By using a different yaml parser when the compiler is ghcjs, the yaml can be parsed and template haskell can then happily make the associated types.
groundhog
andgroundhog-th
can themselves be compiled with ghcjs, as can the user's code with the quasiquotes in it. I tried this in a patch to groundhog (master...imalsogreg:ghcjs) that relies on a small, not-yet-on-hackage ghcjs yaml parser binding (https://github.com/imalsogreg/yaml-ghcjs).groundhog-postgres
(and probably the other backends) still can't be compiled though - they fail at the linking phase because they depend on a c library. So there is no way to get the captivePostgresql
newtype in the client code, which we sometimes need in order to turnKey a BackendSpecific
into Int64 and back. My workaround here is to make aNullDatabese
empty data type andDbDescriptor
instance for it, and use those in the client code to turn Keys into Ints.Those are a couple of options - if you play with ghcjs, do you have any alternative ideas here, or a preference to go forward? Would you be open to pull requests that introduce CPP into groundhog-th to handle the ghcjs case? Thanks for reading a long message!
The text was updated successfully, but these errors were encountered: