lib/sugarcrm/base.rb in sugarcrm-0.9.8 vs lib/sugarcrm/base.rb in sugarcrm-0.9.9
- old
+ new
@@ -25,11 +25,11 @@
class << self # Class methods
def establish_connection(url, user, pass, opts={})
options = {
:debug => false,
- :register_modules => true,
+ :register_modules => true
}.merge(opts)
@debug = options[:debug]
@@connection = SugarCRM::Connection.new(url, user, pass, options)
end
@@ -94,11 +94,13 @@
private
def find_initial(options)
options.update(:limit => 1)
- find_every(options)
+ result = find_by_sql(options)
+ return result.first if result.instance_of? Array # find_by_sql will return an Array if result are found
+ result
end
def find_from_ids(ids, options)
expects_array = ids.first.kind_of?(Array)
return ids.first if expects_array && ids.first.empty?
@@ -150,11 +152,59 @@
def find_every(options)
find_by_sql(options)
end
def find_by_sql(options)
- query = query_from_options(options)
- SugarCRM.connection.get_entry_list(self._module.name, query, options) || nil # return nil instead of false if no results are found
+ # SugarCRM REST API has a bug where, when :limit and :offset options are passed simultaneously, :limit is considered to be the smallest of the two, and :offset is the larger
+ # in addition to allowing querying of large datasets while avoiding timeouts,
+ # this implementation fixes the :limit - :offset bug so that it behaves correctly
+ local_options = {}
+ options.keys.each{|k|
+ local_options[k] = options[k]
+ }
+ local_options.delete(:offset) if local_options[:offset] == 0
+
+ # store the number of records wanted by user, as we'll overwrite :limit option to obtain several slices of records (to avoid timeout issues)
+ nb_to_fetch = local_options[:limit]
+ nb_to_fetch = nb_to_fetch.to_i if nb_to_fetch
+ offset_value = local_options[:offset] || 10 # arbitrary value, must be bigger than :limit used (see comment above)
+ offset_value = offset_value.to_i
+ offset_value.freeze
+ initial_limit = nb_to_fetch.nil? ? offset_value : [offset_value, nb_to_fetch].min # how many records should be fetched on first pass
+ # ensure results are ordered so :limit and :offset option behave in a deterministic fashion
+ local_options = { :order_by => :id }.merge(local_options)
+ local_options.update(:limit => initial_limit) # override original argument
+
+ # get first slice of results
+ # note: to work around a SugarCRM REST API bug, the :limit option must always be smaller than the :offset option
+ # this is the reason this first query is separate (not in the loop): the initial query has a larger limit, so that we can then use the loop
+ # with :limit always smaller than :offset
+ results = SugarCRM.connection.get_entry_list(self._module.name, query_from_options(local_options), local_options)
+ return nil unless results
+ results = Array.wrap(results)
+
+ limit_value = [5, offset_value].min # arbitrary value, must be smaller than :offset used (see comment above)
+ limit_value.freeze
+ local_options = { :order_by => :id }.merge(local_options)
+ local_options.update(:limit => limit_value)
+
+ # a portion of the results has already been queried
+ # update or set the :offset value to reflect this
+ local_options[:offset] ||= results.size
+ local_options[:offset] += offset_value
+
+ # continue fetching results until we either
+ # a) have as many results as the user wants (specified via the original :limit option)
+ # b) there are no more results matching the criteria
+ while result_slice = SugarCRM.connection.get_entry_list(self._module.name, query_from_options(local_options), local_options)
+ results.concat(Array.wrap(result_slice))
+ # make sure we don't return more results than the user requested (via original :limit option)
+ if nb_to_fetch && results.size >= nb_to_fetch
+ return results.slice(0, nb_to_fetch)
+ end
+ local_options[:offset] += local_options[:limit] # update :offset as we get more records
+ end
+ results
end
def query_from_options(options)
# If we dont have conditions, just return an empty query
return "" unless options[:conditions]
\ No newline at end of file