lib/parse_resource/query.rb in parse_resource-1.7.3 vs lib/parse_resource/query.rb in parse_resource-1.8.0

- old
+ new

@@ -12,46 +12,91 @@ criteria[:conditions].merge!(args) self end 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 def include_object(parent) criteria[:include] = parent self end - # deprecating until it works - #def order(attribute) - # attribute = attribute.to_sym if attribute.is_a?(String) - # criteria[:order] = attribute - # self - #end + 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 def skip(skip) criteria[:skip] = skip self end def count(count=1) criteria[:count] = count - #self all end + # Divides the query into multiple chunks if you're running into RestClient::BadRequest errors. + def chunk(count=100) + criteria[:chunk] = count + self + end + + 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 + + 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 + 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 @@ -59,14 +104,61 @@ results = JSON.parse(resp)['results'] return results.map {|r| @klass.model_name.constantize.new(r, false)} end end + 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 + + def first + limit(1) + execute.first + end + def all execute end 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