module ActiveFedora::FinderMethods
def build_query(conditions)
def build_query(conditions) clauses = search_model_clause ? [search_model_clause] : [] clauses += conditions.reject{|c| c.blank?} return "*:*" if clauses.empty? clauses.compact.join(" AND ") end
def class_to_load(resource, cast)
def class_to_load(resource, cast) if @klass == ActiveFedora::Base && cast == false ActiveFedora::Base else # The true class may be a subclass of @klass, so always use from_class_uri resource_class = Model.from_class_uri(has_model_value(resource)) || ActiveFedora::Base unless equivalent_class?(resource_class) raise ActiveFedora::ActiveFedoraError.new("Model mismatch. Expected #{@klass}. Got: #{resource_class}") end resource_class end end
def condition_to_clauses(key, value)
def condition_to_clauses(key, value) unless value.nil? # if the key is a property name, turn it into a solr field if @klass.delegated_attributes.key?(key) # TODO Check to see if `key' is a possible solr field for this class, if it isn't try :searchable instead key = ActiveFedora::SolrQueryBuilder.solr_name(key, :stored_searchable, type: :string) end if value.empty? "-#{key}:['' TO *]" elsif value.is_a? Array value.map { |val| "#{key}:#{solr_escape(val)}" } else key = SOLR_DOCUMENT_ID if (key === :id || key === :id) "#{key}:#{solr_escape(value)}" end end end
def create_query(conditions)
Returns a solr query for the supplied conditions
def create_query(conditions) case conditions when Hash build_query([create_query_from_hash(conditions)]) when String build_query(["(#{conditions})"]) else build_query(conditions) end end
def create_query_from_hash(conditions)
def create_query_from_hash(conditions) conditions.map {|key,value| condition_to_clauses(key, value)}.compact.join(" AND ") end
def equivalent_class?(other_class)
def equivalent_class?(other_class) other_class <= @klass end
def exists?(conditions)
@param[ActiveFedora::Base, String, Hash] object, id or hash of conditions
Returns false if param is false (or nil)
Returns true if object having the id or matching the conditions exists in the repository
def exists?(conditions) conditions = conditions.id if Base === conditions return false if !conditions case conditions when Hash find_with_conditions(conditions, {rows: 1}).present? when String !!find(conditions) else raise ArgumentError, "`conditions' argument must be ActiveFedora::Base, String, or Hash: #{conditions.inspect}" end rescue ActiveFedora::ObjectNotFoundError, Ldp::Gone false end
def find(*args)
(**args)
-
:cast
(Boolean
) -- when true, examine the model and cast it to the first known cModel -
:rows
(Integer
) -- when :all is passed, the maximum number of rows to load from solr
def find(*args) return to_a.find { |*block_args| yield(*block_args) } if block_given? options = args.extract_options! options = options.dup cast = if @klass == ActiveFedora::Base && !options.has_key?(:cast) true else options.delete(:cast) end if options[:sort] # Deprecate sort sometime? sort = options.delete(:sort) options[:order] ||= sort if sort.present? end if options.present? options = args.first unless args.empty? Deprecation.warn(ActiveFedora::Base, "Calling .find with a hash has been deprecated and will not be allowed in active-fedora 10.0. Use .where instead") options = {conditions: options} apply_finder_options(options) else raise ArgumentError, "#{self}.find() expects an id. You provided `#{args.inspect}'" unless args.is_a? Array find_with_ids(args, cast) end end
def find_each( conditions={}, opts={})
(**opts)
-
:cast
(Boolean
) -- when true, examine the model and cast it to the first known cModel
Parameters:
-
opts
(Hash
) -- -
conditions
(Hash
) -- the conditions for the solr search to match
def find_each( conditions={}, opts={}) cast = opts.delete(:cast) find_in_batches(conditions, opts.merge({:fl=>SOLR_DOCUMENT_ID})) do |group| group.each do |hit| begin yield(load_from_fedora(hit[SOLR_DOCUMENT_ID], cast)) rescue Ldp::Gone ActiveFedora::Base.logger.error "Although #{hit[SOLR_DOCUMENT_ID]} was found in Solr, it doesn't seem to exist in Fedora. The index is out of synch." if ActiveFedora::Base.logger end end end end
def find_in_batches conditions, opts={}
def find_in_batches conditions, opts={} opts[:q] = create_query(conditions) opts[:qt] = @klass.solr_query_handler #set default sort to created date ascending unless opts[:sort].present? opts[:sort]= @klass.default_sort_params end batch_size = opts.delete(:batch_size) || 1000 counter = 0 begin counter += 1 response = ActiveFedora::SolrService.instance.conn.paginate counter, batch_size, "select", :params => opts docs = response["response"]["docs"] yield docs end while docs.has_next? end
def find_one(id, cast=nil)
- Example: because the object hydra:dataset1 asserts it is a Dataset (hasModel http://fedora.info/definitions/v4/model#Dataset), return a Dataset object (not a Book). -
Parameters:
-
cast
(Boolean
) -- when true, cast the found object to the class of the first known model defined in it's RELS-EXT -
id
(String
) -- of the object to load
def find_one(id, cast=nil) if where_values.empty? load_from_fedora(id, cast) else conditions = where_values + [ActiveFedora::SolrQueryBuilder.raw_query(SOLR_DOCUMENT_ID, id)] query = conditions.join(" AND ".freeze) to_enum(:find_each, query, {}).to_a.first end end
def find_some(ids, cast)
def find_some(ids, cast) ids.map{|id| find_one(id, cast)} end
def find_take
def find_take if loaded? @records.first else @take ||= limit(1).to_a.first end end
def find_with_conditions(conditions, opts={})
(**opts)
-
:rows
(Array
) -- number of rows to return -
:sort
(Array
) -- a list of fields to sort by
def find_with_conditions(conditions, opts={}) #set default sort to created date ascending unless opts.include?(:sort) opts[:sort]=@klass.default_sort_params end SolrService.query(create_query(conditions), opts) end
def find_with_ids(ids, cast)
def find_with_ids(ids, cast) expects_array = ids.first.kind_of?(Array) return ids.first if expects_array && ids.first.empty? ids = ids.flatten.compact.uniq case ids.size when 0 raise ArgumentError, "Couldn't find #{@klass.name} without an ID" when 1 result = find_one(ids.first, cast) expects_array ? [ result ] : result else find_some(ids, cast) end end
def first
Person.where(name_t: 'Jones').first
@example
Returns the first records that was found.
def first if loaded? @records.first else @first ||= limit(1).to_a[0] end end
def has_model_value(resource)
def has_model_value(resource) best_model_match = nil resource.graph.query([nil, ActiveFedora::RDF::Fcrepo::Model.hasModel, nil]).each do |rg| model_value = Model.from_class_uri(rg.object.to_s) if model_value best_model_match ||= model_value # If there is an inheritance structure, use the most specific case. if best_model_match > model_value best_model_match = model_value end end end best_model_match.to_s end
def last
Person.where(name_t: 'Jones').last
@example
how ActiveRecord would achieve the same behavior.
Returns the last record sorted by id. ID was chosen because this mimics
def last if loaded? @records.last else @last ||= order('id desc').limit(1).to_a[0] end end
def load_from_fedora(id, cast)
def load_from_fedora(id, cast) raise ActiveFedora::ObjectNotFoundError if id.empty? resource = ActiveFedora.fedora.ldp_resource_service.build(klass, id) raise ActiveFedora::ObjectNotFoundError if resource.new? class_to_load(resource, cast).allocate.init_with_resource(resource) # Triggers the find callback end
def search_model_clause
def search_model_clause # The concrete class could could be any subclass of @klass or @klass itself unless @klass == ActiveFedora::Base clauses = ([@klass] + @klass.descendants).map do |k| ActiveFedora::SolrQueryBuilder.construct_query_for_rel(has_model: k.to_s) end clauses.size == 1 ? clauses.first : "(#{clauses.join(" OR ")})" end end
def solr_escape terms
Adds esaping for spaces which are not handled by RSolr.solr_escape
def solr_escape terms RSolr.solr_escape(terms).gsub(/\s+/,"\\ ") end
def take(limit = nil)
Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
Person.take # returns an object fetched by SELECT * FROM people LIMIT 1
If an order is supplied it will be respected.
order. The order will depend on the database implementation.
Gives a record (or N records if a parameter is supplied) without any implied
def take(limit = nil) limit ? limit(limit).to_a : find_take end