Class: Cursory::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/cursory/base.rb

Direct Known Subclasses

Mongoid

Defined Under Namespace

Classes: InvalidCursorError

Constant Summary collapse

MAX_LIMIT =
100
DEFAULT_LIMIT =
10

Instance Method Summary collapse

Constructor Details

#initialize(criteria, params) ⇒ Base

Returns a new instance of Base.



12
13
14
15
16
17
18
# File 'lib/cursory/base.rb', line 12

def initialize criteria, params
  @criteria = criteria
  @sort = params[SORT_KEY]
  @limit = params[LIMIT_KEY]
  @offset = params[OFFSET_KEY]
  @cursor = params[CURSOR_KEY]
end

Instance Method Details

#clamped_limitObject



98
99
100
# File 'lib/cursory/base.rb', line 98

def clamped_limit
  [1, (limit || DEFAULT_LIMIT).to_i, MAX_LIMIT].sort[1]
end

#clamped_offsetObject



36
37
38
# File 'lib/cursory/base.rb', line 36

def clamped_offset
  [0, offset.to_i].max
end

#clause_for_key(key, direction) ⇒ Object



126
127
128
# File 'lib/cursory/base.rb', line 126

def clause_for_key key, direction
  fail UnimplementedError
end

#constrained_searchObject



40
41
42
# File 'lib/cursory/base.rb', line 40

def constrained_search
  fail UnimplementedError
end

#countObject



66
67
68
# File 'lib/cursory/base.rb', line 66

def count
  @count ||= criteria.count
end

#current_cursorObject



52
53
54
# File 'lib/cursory/base.rb', line 52

def current_cursor
  cursor || render_cursor
end

#cursor_clause(key, keys = []) ⇒ Object



116
117
118
119
120
121
122
123
124
# File 'lib/cursory/base.rb', line 116

def cursor_clause(key, keys=[])
  name, direction = key
  Enumerator.new do |y|
    keys.each do |name, direction|
      y.yield clause_for_key(name, 'eq')
    end
    y.yield clause_for_key(name, direction)
  end
end

#cursor_clause_setObject



106
107
108
109
110
111
112
113
114
# File 'lib/cursory/base.rb', line 106

def cursor_clause_set
  keys = []
  Enumerator.new do |y|
    order_keys.each do |key|
      y.yield cursor_clause(key, keys).reduce(&:merge)
      keys << key
    end
  end
end

#cursor_clausesObject



102
103
104
# File 'lib/cursory/base.rb', line 102

def cursor_clauses
  fail UnimplementedError
end

#cursor_data(overrides = {}) ⇒ Object



152
153
154
# File 'lib/cursory/base.rb', line 152

def cursor_data(overrides={})
  (parsed_cursor || {}).merge(overrides)
end

#cursor_idObject



148
149
150
# File 'lib/cursory/base.rb', line 148

def cursor_id
  cursor_data['id']
end

#cursor_objectObject



130
131
132
# File 'lib/cursory/base.rb', line 130

def cursor_object
  @cursor_object ||= uncached_cursor_object
end

#decompose_order_key(k) ⇒ Object



90
91
92
# File 'lib/cursory/base.rb', line 90

def decompose_order_key(k)
  [ k.gsub(/\A[-+]?/,'').to_sym, k.start_with?('-') ? 'desc' : 'asc' ]
end

#modelObject



78
79
80
# File 'lib/cursory/base.rb', line 78

def model
  fail UnimplementedError
end

#model_sortObject



82
83
84
# File 'lib/cursory/base.rb', line 82

def model_sort
  model.respond_to?(:default_sort_key) && model.default_sort_key
end

#next_cursorObject



60
61
62
63
64
# File 'lib/cursory/base.rb', line 60

def next_cursor
  if record_for_next_cursor
    render_cursor cursor_data(id: record_for_next_cursor.id.to_s)
  end
end

#order_clauseObject



94
95
96
# File 'lib/cursory/base.rb', line 94

def order_clause
  fail UnimplementedError
end

#order_keysObject



86
87
88
# File 'lib/cursory/base.rb', line 86

def order_keys
  sort_keys.split(',').map{ |k| decompose_order_key(k) } + [[:id, 'asc']]
end

#pageObject



20
21
22
23
24
25
26
# File 'lib/cursory/base.rb', line 20

def page
  { total_count: count, items: search_results, self: current_cursor }.tap do |p|
    catch(:no_more_results) do
      p[:next] = next_cursor
    end
  end
end

#parsed_cursorObject



142
143
144
145
146
# File 'lib/cursory/base.rb', line 142

def parsed_cursor
  JSON.parse(::Base64.urlsafe_decode64(cursor || 'e30='))
rescue ArgumentError, JSON::ParserError
  raise InvalidCursorError
end

#record_for_next_cursorObject



56
57
58
# File 'lib/cursory/base.rb', line 56

def record_for_next_cursor
  search_results[clamped_limit-1] or throw(:no_more_results)
end

#render_cursor(data = {}) ⇒ Object



138
139
140
# File 'lib/cursory/base.rb', line 138

def render_cursor(data={})
  ::Base64.urlsafe_encode64(JSON.dump(data))
end

#searchObject



28
29
30
# File 'lib/cursory/base.rb', line 28

def search
  constrained_search.send(*search_type)
end

#search_resultsObject



44
45
46
# File 'lib/cursory/base.rb', line 44

def search_results
  @results ||= uncached_search
end

#search_typeObject



32
33
34
# File 'lib/cursory/base.rb', line 32

def search_type
  fail UnimplementedError
end

#sort_keysObject



74
75
76
# File 'lib/cursory/base.rb', line 74

def sort_keys
  sort || model_sort || ''
end

#uncached_countObject



70
71
72
# File 'lib/cursory/base.rb', line 70

def uncached_count
  fail UnimplementedError
end

#uncached_cursor_objectObject



134
135
136
# File 'lib/cursory/base.rb', line 134

def uncached_cursor_object
  fail UnimplementedError
end

#uncached_searchObject



48
49
50
# File 'lib/cursory/base.rb', line 48

def uncached_search
  fail UnimplementedError
end