jgaskins / perpetuity

Persistence gem for Ruby objects using the Data Mapper pattern
http://jgaskins.org/blog/2012/04/20/data-mapper-vs-active-record/
MIT License
250 stars 14 forks source link

Perpetuity assumes that objects respond_to?(:id). #36

Closed booch closed 10 years ago

booch commented 10 years ago

Perpetuity::Mapper#find assumes that it can call object.id for retrieved objects. I don't think we can/should assume that. Everywhere else, we use instance_variable_get via id_for. I think we should use that in #find as well.

Let me know if this makes sense, and you'd like me to create a PR.

jgaskins commented 10 years ago

I assume you're talking about this line?

booch commented 10 years ago

Yes, that's the line. Already started on a patch.

But I also noticed that we're not using the adapters' find methods. And for the in-memory adapter, I've decided to use a Hash based on the ID, so using its find method would be preferable.

jgaskins commented 10 years ago

The way it works is a little confusing, but I'll see if I can explain it coherently. :-)

That block is only used for query generation, not sent to actual retrieved objects. Mapper#select, which is what that line calls, yields a query object which the adapter uses to find out which attributes and comparators you're using. So when we say select { |object| object.id == id }, that gets transformed by the Postgres adapter, for example, into WHERE id = #{id} (sanitized, obviously). The entry point to where that all starts is here (the method called by select to generate the query).

The result of the retrieve method (called by select) isn't a DB result, either. It's a Retrieval, which is actually kind of a misnomer, but it's the best name I could come with at the time. :-) It's a composed query, which lets you use other Enumerable-style methods like sort, take and drop before triggering an actual DB query.