jsonapi-utils
jsonapi-utils copied to clipboard
Non-ActiveRecord paginator support
First and foremost: thanks so much for putting this gem out here!
Problem Statement
I have a service that uses Elasticsearch instead of ActiveRecord and I would like to return the result set counts. Because ActiveRecord::Relation is referenced directly in the counting method, the app explodes. Under the current implementation, my options are to:
- monkeypatch
Pagination.count_recordsin every Elasticsearch-backed service I write - do the counting in the controller and pass it into
jsonapi_renderviaoptions[:count]
Option one is really a strawman, and it felt odd to sprinkle options: { count: MyEsModel.count( params ) } in every single controller action across multiple controllers in several projects.
Proposed Contribution
I extracted the underlying counting interface in to a RecordCounter module that responds to count( records, params = {}, options ={} ) and loops through dedicated Counter classes that know how to count a specific class type. So like, ActiveRecord::Relation objects go to the ActiveRecordCounter and Arrays go to the ArrayCounter class.
The #{Type}Counter classes register themselves with RecordCounter on declaration with counts #{Type.to_s.underscore} making adding new counters as easy as just declaring them in your project.
What this does
I will admit that this is a somewhat involved change, but there are several benefits to this added complexity. It:
- eliminates the hard dependency on
ActiveRecord::Relationin the counting mechanism - allows for easy extensions to counting, both in adding counting for other backend technologies, as well as modifying existing counting functionality without having to modify
JSONAPI::Utils
Example
To use my use case, an Elasticsearch-backed system would implement a counter approximately like so:
class ElasticsearchCounter < JSONAPI::Utils::Support::Pagination::RecordCounter::BaseCounter
counts "elasticsearch/persistence/repository/response/results"
# the one thing we have to define
def count
# not the actual implementation
model_class = @records.first.class
query = model_class.query_from_params @params
model_class.count query
end
end
@tiagopog, I would love some feedback on this.
@tiagopog bump?
@tiagopog have you had a chance to look at this at all?