
[cross-posting to web-devel]
On Wed, Sep 12, 2012 at 6:28 AM, Leon Smith
I am curious to know why persistent is a dependency, given that it sounds like esqueleto focuses on generating raw SQL.
Is it to get a more consistent interface across multiple database backends? To handle schemas or migrations? Something else I'm missing entirely?
TL;DR: Mainly the schema. Esqueleto could stop using persistent if we wanted but I don't know how many people would like to see this working and it is by no means trivial. Its main use of persistent is actually on the frontend, on the EDSL that you use. Using persistent we get a type-safe representation of the schema for free: entities and their fields. So when you say where_ (p ^. BlogPostTitle ==. val title) that BlogPostTitle is a constructor representing a field of entity BlogPost, which was created by persistent. The fact that p is a BlogPost is type-checked. The fact that title is, e.g., Text is type-checked. If I didn't use persistent, I'd have to ask the user to write this boilerplate code himself. If I didn't use persistent but the user did, it would be probably just a matter of implementing a lot of type class instances with trivial definitions. If neither I not my user used persistent, you'd probably have to implement a lot more (especially for the next point). It's also very convenient to use persistent on the backend. It already has everything you need to serialize and deserialize fields and entities, and a few bits more (such as escaping). This is also about schema, and we could also drop persistent if we gave the user the responsibility of writing a lot of boilerplate. We decided to use persistent as esqueleto's backend also because that's what we use on our company. We don't know of any other alternative that brings what persistent has for us: semi-intelligent migrations, not so much boilerplate due to TH, good support to MySQL via Bryan O'Sullivan's libraries (this bit is persistent-mysql and we developed the library in-house), type-safety on everything it provides (and now much more due to esqueleto), and non-slowness (I've never seen a benchmark between database APIs, but we know that persistent---and esqueleto---has been written with performance in mind). Even if there was an alternative, it would be very wasteful to change all of our codebase *unless* it brought something nice to the table that persistent does not have. Having said all that, it *may* be possible to abstract persistent out of esqueleto and avoid boilerplate for persistent's users by using the ConstraintKinds extension. All constraints that you see on the EDSL's interface could come from type families inside Esqueleto's type class. In order for this abstraction to be useful, we'd also need to abstract persistent away from the SQL backend, which may require a type class with a lot more internal methods but which persistent users will never need to see. This may be a nice idea should there be anyone wanting to use esqueleto without persistent. But, like I said above, you'd still need to define some boilerplate about your entities. I see two kinds of users that may like such approach: - Users that use completely raw interfaces (such as directly using {mysql,postgresql}-simple libraries). They will need to define a lot boilerplate by themselves, including the SQL backend type class. I'd say that these users should instead define a persistent schema, which will also need some boilerplate but a lot less, and you get persistent for free in the process. - Users of HaskellDB that need to issue a couple of raw queries here and there. It would be technically very interesting to use both approaches at the same time. Given that HaskellDB already has constructors for entities and fields, it would be just a matter of somehow teaching esqueleto how to use it (which may be easy but I never thought about it). However, I wonder how many exist on this category. So, while possible to stop using persistent, I'll probably not do anything in this direction unless I see that there is some interest in doing so (and not only for the sake of abstracting things). However, I'd accept a pull request for this in a heartbeat *if* it didn't add any boilerplate for persistent users. I could also accept something that incurs boilerplate overhead for persistent users, but it would not be in a heartbeat =). Cheers! -- Felipe.