Class: Miscellany::SlicedResponse::Slice

Inherits:
Object
  • Object
show all
Defined in:
lib/miscellany/controller/sliced_response.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(items, options = {}) ⇒ Slice

Returns a new instance of Slice.



76
77
78
79
# File 'lib/miscellany/controller/sliced_response.rb', line 76

def initialize(items, options={})
  @items = items
  @options = options
end

Instance Attribute Details

#itemsObject (readonly)

Returns the value of attribute items.



73
74
75
# File 'lib/miscellany/controller/sliced_response.rb', line 73

def items
  @items
end

#optionsObject (readonly)

Returns the value of attribute options.



74
75
76
# File 'lib/miscellany/controller/sliced_response.rb', line 74

def options
  @options
end

#page_numberObject

Returns the value of attribute page_number.



70
71
72
# File 'lib/miscellany/controller/sliced_response.rb', line 70

def page_number
  @page_number
end

#page_sizeObject

Returns the value of attribute page_size.



70
71
72
# File 'lib/miscellany/controller/sliced_response.rb', line 70

def page_size
  @page_size
end

#slice_endObject

Returns the value of attribute slice_end.



69
70
71
# File 'lib/miscellany/controller/sliced_response.rb', line 69

def slice_end
  @slice_end
end

#slice_startObject

Returns the value of attribute slice_start.



69
70
71
# File 'lib/miscellany/controller/sliced_response.rb', line 69

def slice_start
  @slice_start
end

#sortObject

Returns the value of attribute sort.



71
72
73
# File 'lib/miscellany/controller/sliced_response.rb', line 71

def sort
  @sort
end

Class Method Details

.build(queryset, arg, options = {}) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/miscellany/controller/sliced_response.rb', line 81

def self.build(queryset, arg, options={})
  new(queryset, options).tap do |slice|
    if arg.is_a?(Array)
      slice_bounds = arg
    elsif arg.is_a?(String)
      slice_bounds = arg.split(':').map(&:to_i)
    elsif arg.is_a?(Range)
      slice_bounds = arg.minmax
    elsif arg.respond_to? :[]
      if arg[:slice] == 'all' || arg[:page] == 'all'
        slice_bounds = [0, -1]
      elsif arg[:slice].present?
        slice_bounds = arg[:slice].split(':').map(&:to_i)
      else
        # :default_page_size and :default_size are two names callers use for the
        # same thing; honor either so a caller passing only one isn't left with 0.
        default_page_size = options[:default_page_size] || options[:default_size]
        page_size = slice[:page_size] = (arg[:page_size] || default_page_size).to_i
        if page_size < 1
          raise HttpErrorHandling::HttpError.new(message: "page_size must be at least 1")
        end

        # Clamped rather than rejected, so that a page past either end of the
        # collection stays a valid (if empty) request. Matches ComplexQuery#page.
        page_number = slice[:page_number] = [(arg[:page] || 1).to_i, 1].max
        slice_bounds = [(page_number - 1) * page_size, page_number * page_size]
      end

      begin
        slice[:sort] = options[:sort_parser]&.parse(arg[:sort], ignore_errors: true, default: true)
      rescue Miscellany::SortLang::Parser::SortParsingError => e
        raise HttpErrorHandling::HttpError.new(message: e.message)
      end
    end

    if slice_bounds.present?
      slice[:slice_start] = slice_bounds[0]
      slice[:slice_end] = slice_bounds[1]
    end

    if slice[:slice_end] == -1
      raise HttpErrorHandling::HttpError.new(message: "cannot request whole collection") unless options[:allow_all]
    else
      if options[:max_size] && (slice[:slice_end] - slice[:slice_start]) > [options[:max_size], options[:default_size]].max
        raise HttpErrorHandling::HttpError.new(message: "cannot request more than #{options[:max_size]} objects")
      end
    end
  end
end

Instance Method Details

#[](key) ⇒ Object



131
132
133
# File 'lib/miscellany/controller/sliced_response.rb', line 131

def [](key)
  send(key)
end

#[]=(key, val) ⇒ Object



135
136
137
# File 'lib/miscellany/controller/sliced_response.rb', line 135

def []=(key, val)
  send(:"#{key}=", val)
end

#render_jsonObject



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/miscellany/controller/sliced_response.rb', line 139

def render_json
  return @rendered_json if defined?(@rendered_json)

  json = @rendered_json = {
    slice_start: slice_start,
    slice_end: slice_end,
  }

  rendered_items

  if page_size.present?
    json[:page] ||= page_number
    json[:page_size] ||= page_size
  end

  if total_item_count.present?
    json[:total_count] ||= total_item_count
    json[:page_count] ||= (total_item_count.to_f / page_size).ceil if page_size.present?
  end

  if sort.present?
    json[:sort] ||= sort.map do |s|
      "#{s[:key] || s[:column]} #{s[:order] || 'ASC'}"
    end.join(', ')
  end

  json[:slice_start] ||= 0
  json[:slice_end] ||= total_item_count

  json[:items] = rendered_items

  json
end

#rendered_jsonObject



172
# File 'lib/miscellany/controller/sliced_response.rb', line 172

def rendered_json; render_json; end