Skip to content
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

Support for first, limit, group and order #520

Closed
noctivityinc opened this issue Feb 10, 2019 · 6 comments
Closed

Support for first, limit, group and order #520

noctivityinc opened this issue Feb 10, 2019 · 6 comments

Comments

@noctivityinc
Copy link

Is there any way to add support for

  • limit
  • first (could be one with limit)
  • order
  • group

We basically just need a way to either include or pass those as params, especially LIMIT.

With limit we can easily add our own Model.first method.

If someone points me in the right direction to add these myself, I can try to incorporate them.

@zacharywelch
Copy link
Collaborator

Your best bet is to define scopes or class methods on the model, since Her can't predict what conventions an API follows for each of these options. Some examples

class User
  include Her::Model

  # @example
  #
  #   User.page(2) # Fetched via GET "/users?page=2
  scope :page, ->(value) { where(page: value) }

  # @example
  #
  #   User.limit(100) # Fetched via GET "/users?limit=100
  scope :limit, ->(value) { where(limit: value) }

  # @example
  #
  #   User.order(:name) # Fetched via GET "/users?sort=name_asc
  def self.order(params = {})
    params = Hash[params, :asc] if params.is_a? ::Symbol
    where(sort: params.flatten.join('_'))
  end
end

Another idea would be to move these into a base class or mixin so they could be reused.

@noctivityinc
Copy link
Author

Problem with that is that I'm wrapping the where statement as per an earlier post. It's almost like I need the ability to do something like

scope :limit, -> (value) { param(limit: value) }

where the param method would accept any parameter.

Best,

Josh

@zacharywelch
Copy link
Collaborator

What's the purpose behind the param method? Can you provide a sample of what the HTTP request would look like?

@zacharywelch
Copy link
Collaborator

Ok, see now where this particular problem is discussed in #519. Let's move the conversation over there and see if we can find a solution since we covered support of limit, page, etc. 😺

@noctivityinc
Copy link
Author

Ok. So.

I have overridden the where method for Her like such:

module Her
  module Model
    class Relation
      # Add a query string parameter
      #
      # @example
      #   @users = User.all
      #   # Fetched via GET "/users"
      #
      # @example
      #   @users = User.where(:approved => 1).all
      #   # Fetched via GET "/users?approved=1"
      def where(params = {})
        return self if params.blank? && !@_fetch.nil?
        clone.tap do |r|
          r.params = r.params.merge({where: params})
          r.clear_fetch_cache!
        end
      end
      alias all where
    end

so that where is automatically wrapped in a "where" attribute. Then on the API I have this...

   @devices = ::Device.all

    filters = params[:where]
    if filters.present?
      filters.keys.each do |key|
        if key == 'term'
          @devices = @devices.where(filters[key])
        else
          @devices = @devices.where("#{key}" => filters[key])
        end
      end
    end

so when I user Her I do something like:

Device.where(active: true) =>  https://api.example.com/devices?where[active]=true

or 

Device.where({term: ["created_at > ?",1.month.ago]}

And all of the above work fine and let me run any query.

As you can see, because of this I can't just put things like limit, order, etc into the where statement, which doesn't make sense logically anyway. If, however, I had a catch-all method, like param I could do:

def first
  Device.param({limit: 1, order: 'created_at desc'})
end

and then on the API:

passed_params = params[:param]
if passed_params.present?
  passed_params.each do |key|
     case key
        when 'limit'
           @device = @device.limit(passed_params[:key])
       when 'order'
          ....
     end
  end
end

make sense?

@noctivityinc
Copy link
Author

@zacharywelch that one was me also :)

That addresses more mutating existing methods (I didnt use any of those btw) instead of adding new ones.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants