Class: Query

Inherits:
Object
  • Object
show all
Defined in:
lib/parse_resource/query.rb

Instance Method Summary collapse

Constructor Details

#initialize(klass) ⇒ Query

Returns a new instance of Query.



3
4
5
# File 'lib/parse_resource/query.rb', line 3

def initialize(klass)
  @klass = klass
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args, &block) ⇒ Object



138
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
# File 'lib/parse_resource/query.rb', line 138

def method_missing(meth, *args, &block)
  method_name = method_name.to_s
  if method_name.start_with?("find_by_")
    attrib   = method_name.gsub(/^find_by_/,"")
    finder_name = "find_all_by_#{attrib}"

    define_singleton_method(finder_name) do |target_value|
      where({attrib.to_sym => target_value}).first
    end

    send(finder_name, args[0])

  elsif method_name.start_with?("find_all_by_")
    attrib   = method_name.gsub(/^find_all_by_/,"")
    finder_name = "find_all_by_#{attrib}"

    define_singleton_method(finder_name) do |target_value|
      where({attrib.to_sym => target_value}).all
    end

    send(finder_name, args[0])
  end

  if Array.method_defined?(meth)
    all.send(meth, *args, &block)
  else
    super
  end
end

Instance Method Details

#allObject



134
135
136
# File 'lib/parse_resource/query.rb', line 134

def all
  execute
end

#chunk(count = 100) ⇒ Object

Divides the query into multiple chunks if you’re running into RestClient::BadRequest errors.



50
51
52
53
# File 'lib/parse_resource/query.rb', line 50

def chunk(count=100)
  criteria[:chunk] = count
  self
end

#chunk_results(params = {}) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/parse_resource/query.rb', line 109

def chunk_results(params={})
  criteria[:limit] ||= 100
  
  start_row = criteria[:skip].to_i
  end_row = [criteria[:limit].to_i - start_row - 1, 1].max
  result = []
  
  # Start at start_row, go to end_row, get results in chunks
  (start_row..end_row).each_slice(criteria[:chunk].to_i) do |slice|
    params[:skip] = slice.first
    params[:limit] = slice.length # Either the chunk size or the end of the limited results

    resp = @klass.resource.get(:params => params)
    results = JSON.parse(resp)['results']
    result = result + results.map {|r| @klass.model_name.constantize.new(r, false)}
    break if results.length < params[:limit] # Got back fewer than we asked for, so exit.
  end
  result
end

#count(count = 1) ⇒ Object



44
45
46
47
# File 'lib/parse_resource/query.rb', line 44

def count(count=1)
  criteria[:count] = count
  all
end

#criteriaObject



7
8
9
# File 'lib/parse_resource/query.rb', line 7

def criteria
  @criteria ||= { :conditions => {} }
end

#executeObject



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/parse_resource/query.rb', line 87

def execute
  params = {}
  params.merge!({:where => criteria[:conditions].to_json}) if criteria[:conditions]
  params.merge!({:limit => criteria[:limit].to_json}) if criteria[:limit]
  params.merge!({:skip => criteria[:skip].to_json}) if criteria[:skip]
  params.merge!({:count => criteria[:count].to_json}) if criteria[:count]
  params.merge!({:include => criteria[:include]}) if criteria[:include]
  params.merge!({:order => criteria[:order]}) if criteria[:order]

  return chunk_results(params) if criteria[:chunk]

  resp = @klass.resource.get(:params => params)
  
  if criteria[:count] == 1
    results = JSON.parse(resp)['count']
    return results.to_i
  else
    results = JSON.parse(resp)['results']
    return results.map {|r| @klass.model_name.constantize.new(r, false)}
  end
end

#firstObject



129
130
131
132
# File 'lib/parse_resource/query.rb', line 129

def first
  limit(1)
  execute.first
end

#include_object(parent) ⇒ Object



24
25
26
27
# File 'lib/parse_resource/query.rb', line 24

def include_object(parent)
  criteria[:include] = parent
  self
end

#limit(limit) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/parse_resource/query.rb', line 16

def limit(limit)
  # If > 1000, set chunking, because large queries over 1000 need it with Parse
  chunk(1000) if limit > 1000

  criteria[:limit] = limit
  self
end

#near(klass, geo_point, options) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/parse_resource/query.rb', line 55

def near(klass, geo_point, options)
  if geo_point.is_a? Array
    geo_point = ParseGeoPoint.new :latitude => geo_point[0], :longitude => geo_point[1]
  end

  query = { "$nearSphere" => geo_point.to_pointer }
  if options[:maxDistanceInMiles]
    query["$maxDistanceInMiles"] = options[:maxDistanceInMiles]
  elsif options[:maxDistanceInRadians]
    query["$maxDistanceInRadians"] = options[:maxDistanceInRadians]
  elsif options[:maxDistanceInKilometers]
    query["$maxDistanceInKilometers"] = options[:maxDistanceInKilometers]
  end

  criteria[:conditions].merge!({ klass => query })
  self
end

#order(attr) ⇒ Object



29
30
31
32
33
34
35
36
37
# File 'lib/parse_resource/query.rb', line 29

def order(attr)
  orders = attr.split(" ")
  if orders.count > 1
    criteria[:order] = orders.last.downcase == "desc" ? "-#{orders.first}" : "#{orders.first}"
  else
    criteria[:order] = orders.first
  end
  self
end

#respond_to?(meth) ⇒ Boolean

Returns:

  • (Boolean)


168
169
170
171
172
173
174
# File 'lib/parse_resource/query.rb', line 168

def respond_to?(meth)
  if Array.method_defined?(meth)
    true
  else
    super
  end
end

#skip(skip) ⇒ Object



39
40
41
42
# File 'lib/parse_resource/query.rb', line 39

def skip(skip)
 criteria[:skip] = skip
 self
end

#where(args) ⇒ Object



11
12
13
14
# File 'lib/parse_resource/query.rb', line 11

def where(args)
  criteria[:conditions].merge!(args)
  self
end

#within_box(klass, geo_point_south, geo_point_north) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/parse_resource/query.rb', line 73

def within_box(klass, geo_point_south, geo_point_north)
  if geo_point_south.is_a? Array
    geo_point_south = ParseGeoPoint.new :latitude => geo_point_south[0], :longitude => geo_point_south[1]
  end

  if geo_point_north.is_a? Array
    geo_point_north = ParseGeoPoint.new :latitude => geo_point_north[0], :longitude => geo_point_north[1]
  end

  query = { "$within" => { "$box" => [geo_point_south.to_pointer, geo_point_north.to_pointer]}}
  criteria[:conditions].merge!({ klass => query })
  self
end