Included Modules

Class Index [+]

Quicksearch

DataMapper::Query

Query class represents a query which will be run against the data-store. Generally Query objects can be found inside Collection objects.

Constants

OPTIONS

Attributes

repository[R]

Returns the repository query should be executed in

Set in cases like the following:

@example

  Document.all(:repository => :medline)

@return [Repository]

  the Repository to retrieve results from

@api semipublic

model[R]

Returns model (class) that is used to instantiate objects from query result returned by adapter

@return [Model]

  the Model to retrieve results from

@api semipublic

fields[R]

Returns the fields

Set in cases like the following:

@example

  Document.all(:fields => [:title, :vernacular_title, :abstract])

@return [PropertySet]

  the properties in the Model that will be retrieved

@api semipublic

conditions[R]

Returns the conditions of the query

In the following example:

@example

  Team.all(:wins.gt => 30, :conference => 'East')

Conditions are “greater than” operator for “wins” field and exact match operator for “conference”.

@return [Array]

  the conditions that will be used to scope the results

@api semipublic

offset[R]

Returns the offset query uses

Set in cases like the following:

@example

  Document.all(:offset => page.offset)

@return [Integer]

  the offset of the results

@api semipublic

limit[R]

Returns the limit query uses

Set in cases like the following:

@example

  Document.all(:limit => 10)

@return [Integer, nil]

  the maximum number of results

@api semipublic

order[R]

Returns the order

Set in cases like the following:

@example

  Document.all(:order => [:created_at.desc, :length.desc])

query order is a set of two ordering rules, descending on “created_at“ field and descending again on “length” field

@return [Array]

  the order of results

@api semipublic

options[R]

Returns the original options

@return [Hash]

  the original options

@api private

Public Class Methods

new(repository, model, options = {}) click to toggle source

Initializes a Query instance

@example

 JournalIssue.all(:repository => :medline, :created_on.gte => Date.today - 7)

initialized a query with repository defined with name :medline, model JournalIssue and options { :created_on.gte => Date.today - 7 }

@param [Repository] repository

  the Repository to retrieve results from

@param [Model] model

  the Model to retrieve results from

@param [Hash] options

  the conditions and scope

@api semipublic

     # File lib/dm-core/query.rb, line 714
714:     def initialize(repository, model, options = {})
715:       assert_kind_of 'repository', repository, Repository
716:       assert_kind_of 'model',      model,      Model
717: 
718:       @repository = repository
719:       @model      = model
720:       @options    = options.dup.freeze
721: 
722:       repository_name = repository.name
723: 
724:       @properties    = @model.properties(repository_name)
725:       @relationships = @model.relationships(repository_name)
726: 
727:       assert_valid_options(@options)
728: 
729:       @fields       = @options.fetch :fields,       @properties.defaults
730:       @links        = @options.key?(:links) ? @options[:links].dup : []
731:       @conditions   = Conditions::Operation.new(:null)
732:       @offset       = @options.fetch :offset,       0
733:       @limit        = @options.fetch :limit,        nil
734:       @order        = @options.fetch :order,        @model.default_order(repository_name)
735:       @unique       = @options.fetch :unique,       true
736:       @add_reversed = @options.fetch :add_reversed, false
737:       @reload       = @options.fetch :reload,       false
738:       @raw          = false
739: 
740:       merge_conditions([ DataMapper::Ext::Hash.except(@options, *OPTIONS), @options[:conditions] ])
741:       normalize_options
742:     end
target_conditions(source, source_key, target_key) click to toggle source

Extract conditions to match a Resource or Collection

@param [Array, Collection, Resource] source

  the source to extract the values from

@param [ProperySet] source_key

  the key to extract the value from the resource

@param [ProperySet] target_key

  the key to match the resource with

@return [AbstractComparison, AbstractOperation]

  the conditions to match the resources with

@api private

    # File lib/dm-core/query.rb, line 49
49:     def self.target_conditions(source, source_key, target_key)
50:       target_key_size = target_key.size
51:       source_values   = []
52: 
53:       if source.nil?
54:         source_values << [ nil ] * target_key_size
55:       else
56:         Array(source).each do |resource|
57:           next unless source_key.loaded?(resource)
58:           source_value = source_key.get!(resource)
59:           next unless target_key.valid?(source_value)
60:           source_values << source_value
61:         end
62:       end
63: 
64:       source_values.uniq!
65: 
66:       if target_key_size == 1
67:         target_key = target_key.first
68:         source_values.flatten!
69: 
70:         if source_values.size == 1
71:           Conditions::EqualToComparison.new(target_key, source_values.first)
72:         else
73:           Conditions::InclusionComparison.new(target_key, source_values)
74:         end
75:       else
76:         or_operation = Conditions::OrOperation.new
77: 
78:         source_values.each do |source_value|
79:           and_operation = Conditions::AndOperation.new
80: 
81:           target_key.zip(source_value) do |property, value|
82:             and_operation << Conditions::EqualToComparison.new(property, value)
83:           end
84: 
85:           or_operation << and_operation
86:         end
87: 
88:         or_operation
89:       end
90:     end
target_query(repository, model, source) click to toggle source

@param [Repository] repository

  the default repository to scope the query within

@param [Model] model

  the default model for the query

@param [#, Enumerable] source

  the source to generate the query with

@return [Query]

  the query to match the resources with

@api private

     # File lib/dm-core/query.rb, line 103
103:     def self.target_query(repository, model, source)
104:       if source.respond_to?(:query)
105:         source.query
106:       elsif source.kind_of?(Enumerable)
107:         key        = model.key(repository.name)
108:         conditions = Query.target_conditions(source, key, key)
109:         repository.new_query(model, :conditions => conditions)
110:       else
111:         raise ArgumentError, "+source+ must respond to #query or be an Enumerable, but was #{source.class}"
112:       end
113:     end

Public Instance Methods

&(other) click to toggle source
Alias for: intersection
+(other) click to toggle source
Alias for: union
-(other) click to toggle source
Alias for: difference
[](*args) click to toggle source
Alias for: slice
add_reversed?() click to toggle source

Indicates if each result should be returned in reverse order

Set in cases like the following:

@example

  Document.all(:limit => 5).reverse

Note that :add_reversed option may be used in conditions directly, but this is rarely the case

@return [Boolean]

  true if the results should be reversed, false if not

@api private

     # File lib/dm-core/query.rb, line 248
248:     def add_reversed?
249:       @add_reversed
250:     end
clear() click to toggle source

Clear conditions

@return [self]

@api semipublic

     # File lib/dm-core/query.rb, line 472
472:     def clear
473:       @conditions = Conditions::Operation.new(:null)
474:       self
475:     end
condition_properties() click to toggle source

Get the properties used in the conditions

@return [Set]

 Set of properties used in the conditions

@api private

     # File lib/dm-core/query.rb, line 627
627:     def condition_properties
628:       properties = Set.new
629: 
630:       each_comparison do |comparison|
631:         next unless comparison.respond_to?(:subject)
632:         subject = comparison.subject
633:         properties << subject if subject.kind_of?(Property)
634:       end
635: 
636:       properties
637:     end
difference(other) click to toggle source

Return the difference with another query

@param [Query] other

  the other query

@return [Query]

  the difference of the query and other

@api semipublic

     # File lib/dm-core/query.rb, line 461
461:     def difference(other)
462:       set_operation(:difference, other)
463:     end
Also aliased as: -
filter_records(records) click to toggle source

Takes an Enumerable of records, and destructively filters it. First finds all matching conditions, then sorts it, then does offset & limit

@param [Enumerable] records

  The set of records to be filtered

@return [Enumerable]

  Whats left of the given array after the filtering

@api semipublic

     # File lib/dm-core/query.rb, line 488
488:     def filter_records(records)
489:       records = records.uniq           if unique?
490:       records = match_records(records) if conditions
491:       records = sort_records(records)  if order
492:       records = limit_records(records) if limit || offset > 0
493:       records
494:     end
inspect() click to toggle source

Returns detailed human readable string representation of the query

@return [String] detailed string representation of the query

@api semipublic

     # File lib/dm-core/query.rb, line 604
604:     def inspect
605:       attrs = [
606:         [ :repository, repository.name ],
607:         [ :model,      model           ],
608:         [ :fields,     fields          ],
609:         [ :links,      links           ],
610:         [ :conditions, conditions      ],
611:         [ :order,      order           ],
612:         [ :limit,      limit           ],
613:         [ :offset,     offset          ],
614:         [ :reload,     reload?         ],
615:         [ :unique,     unique?         ],
616:       ]
617: 
618:       "#<#{self.class.name} #{attrs.map { |key, value| "@#{key}=#{value.inspect}" }.join(' ')}>"
619:     end
intersection(other) click to toggle source

Return the intersection with another query

@param [Query] other

  the other query

@return [Query]

  the intersection of the query and other

@api semipublic

     # File lib/dm-core/query.rb, line 445
445:     def intersection(other)
446:       return dup if self == other
447:       set_operation(:intersection, other)
448:     end
Also aliased as: &
limit_records(records) click to toggle source

Limits a set of records by the offset and/or limit

@param [Enumerable] records

  A list of records to sort

@return [Enumerable]

  The offset & limited records

@api semipublic

     # File lib/dm-core/query.rb, line 538
538:     def limit_records(records)
539:       offset = self.offset
540:       limit  = self.limit
541:       size   = records.size
542: 
543:       if offset > size - 1
544:         []
545:       elsif (limit && limit != size) || offset > 0
546:         records[offset, limit || size] || []
547:       else
548:         records.dup
549:       end
550:     end
match_records(records) click to toggle source

Filter a set of records by the conditions

@param [Enumerable] records

  The set of records to be filtered

@return [Enumerable]

  Whats left of the given array after the matching

@api semipublic

     # File lib/dm-core/query.rb, line 505
505:     def match_records(records)
506:       conditions = self.conditions
507:       records.select { |record| conditions.matches?(record) }
508:     end
merge(other) click to toggle source

Similar to Query#update, but acts on a duplicate.

@param [Query, Hash] other

  other query to merge with

@return [Query]

  updated duplicate of original query

@api semipublic

     # File lib/dm-core/query.rb, line 385
385:     def merge(other)
386:       dup.update(other)
387:     end
raw?() click to toggle source

Indicates if the Query has raw conditions

@return [Boolean]

  true if the query has raw conditions, false if not

@api semipublic

     # File lib/dm-core/query.rb, line 282
282:     def raw?
283:       @raw
284:     end
relative(options) click to toggle source

Builds and returns new query that merges original with one given, and slices the result with respect to :limit and :offset options

This method is used by Collection to concatenate options from multiple chained calls in cases like the following:

@example

  author.books.all(:year => 2009).all(:published => false)

@api semipublic

     # File lib/dm-core/query.rb, line 402
402:     def relative(options)
403:       options = options.to_hash
404: 
405:       offset = nil
406:       limit  = self.limit
407: 
408:       if options.key?(:offset) && (options.key?(:limit) || limit)
409:         options = options.dup
410:         offset  = options.delete(:offset)
411:         limit   = options.delete(:limit) || limit - offset
412:       end
413: 
414:       query = merge(options)
415:       query = query.slice!(offset, limit) if offset
416:       query
417:     end
reload?() click to toggle source

Indicates if the Query results should replace the results in the Identity Map

  TODO: needs example

@return [Boolean]

  true if the results should be reloaded, false if not

@api semipublic

     # File lib/dm-core/query.rb, line 260
260:     def reload?
261:       @reload
262:     end
reverse() click to toggle source

Returns a new Query with a reversed order

@example

  Document.all(:limit => 5).reverse

Will execute a single query with correct order

@return [Query]

  new Query with reversed order

@api semipublic

     # File lib/dm-core/query.rb, line 308
308:     def reverse
309:       dup.reverse!
310:     end
reverse!() click to toggle source

Reverses the sort order of the Query

@example

  Document.all(:limit => 5).reverse

Will execute a single query with original order and then reverse collection in the Ruby space

@return [Query]

  self

@api semipublic

     # File lib/dm-core/query.rb, line 325
325:     def reverse!
326:       # reverse the sort order
327:       @order.map! { |direction| direction.dup.reverse! }
328: 
329:       # copy the order to the options
330:       @options = @options.merge(:order => @order).freeze
331: 
332:       self
333:     end
slice(*args) click to toggle source

Slices collection by adding limit and offset to the query, so a single query is executed

@example

  Journal.all(:limit => 10).slice(3, 5)

will execute query with the following limit and offset (when repository uses DataObjects adapter, and thus queries use SQL):

  LIMIT 5 OFFSET 3

@api semipublic

     # File lib/dm-core/query.rb, line 566
566:     def slice(*args)
567:       dup.slice!(*args)
568:     end
Also aliased as: []
slice!(*args) click to toggle source

Slices collection by adding limit and offset to the query, so a single query is executed

@example

  Journal.all(:limit => 10).slice!(3, 5)

will execute query with the following limit (when repository uses DataObjects adapter, and thus queries use SQL):

  LIMIT 10

and then takes a slice of collection in the Ruby space

@api semipublic

     # File lib/dm-core/query.rb, line 588
588:     def slice!(*args)
589:       offset, limit = extract_slice_arguments(*args)
590: 
591:       if self.limit || self.offset > 0
592:         offset, limit = get_relative_position(offset, limit)
593:       end
594: 
595:       update(:offset => offset, :limit => limit)
596:     end
sort_records(records) click to toggle source

Sorts a list of Records by the order

@param [Enumerable] records

  A list of Resources to sort

@return [Enumerable]

  The sorted records

@api semipublic

     # File lib/dm-core/query.rb, line 519
519:     def sort_records(records)
520:       sort_order = order.map { |direction| [ direction.target, direction.operator == :asc ] }
521: 
522:       records.sort_by do |record|
523:         sort_order.map do |(property, ascending)|
524:           Sort.new(record_value(record, property), ascending)
525:         end
526:       end
527:     end
sorted_fields() click to toggle source

Return a list of fields in predictable order

@return [Array]

  list of fields sorted in deterministic order

@api private

     # File lib/dm-core/query.rb, line 645
645:     def sorted_fields
646:       fields.sort_by { |property| property.hash }
647:     end
to_hash() click to toggle source

Hash representation of a Query

@return [Hash]

  Hash representation of a Query

@api private

     # File lib/dm-core/query.rb, line 666
666:     def to_hash
667:       {
668:         :repository   => repository.name,
669:         :model        => model.name,
670:         :fields       => fields,
671:         :links        => links,
672:         :conditions   => conditions,
673:         :offset       => offset,
674:         :limit        => limit,
675:         :order        => order,
676:         :unique       => unique?,
677:         :add_reversed => add_reversed?,
678:         :reload       => reload?,
679:       }
680:     end
to_relative_hash() click to toggle source

Extract options from a Query

@param [Query] query

  the query to extract options from

@return [Hash]

  the options to use to initialize the new query

@api private

     # File lib/dm-core/query.rb, line 691
691:     def to_relative_hash
692:       DataMapper::Ext::Hash.only(to_hash, :fields, :order, :unique, :add_reversed, :reload)
693:     end
to_subquery() click to toggle source

Transform Query into subquery conditions

@return [AndOperation]

  a subquery for the Query

@api private

     # File lib/dm-core/query.rb, line 655
655:     def to_subquery
656:       collection = model.all(merge(:fields => model_key))
657:       Conditions::Operation.new(:and, Conditions::Comparison.new(:in, self_relationship, collection))
658:     end
union(other) click to toggle source

Return the union with another query

@param [Query] other

  the other query

@return [Query]

  the union of the query and other

@api semipublic

     # File lib/dm-core/query.rb, line 428
428:     def union(other)
429:       return dup if self == other
430:       set_operation(:union, other)
431:     end
Also aliased as: |, +
unique?() click to toggle source

Indicates if the Query results should be unique

  TODO: needs example

@return [Boolean]

  true if the results should be unique, false if not

@api semipublic

     # File lib/dm-core/query.rb, line 272
272:     def unique?
273:       @unique
274:     end
update(other) click to toggle source

Updates the Query with another Query or conditions

Pretty unrealistic example:

@example

  Journal.all(:limit => 2).query.limit                     # => 2
  Journal.all(:limit => 2).query.update(:limit => 3).limit # => 3

@param [Query, Hash] other

  other Query or conditions

@return [Query]

  self

@api semipublic

     # File lib/dm-core/query.rb, line 351
351:     def update(other)
352:       other_options = if kind_of?(other.class)
353:         return self if self.eql?(other)
354:         assert_valid_other(other)
355:         other.options
356:       else
357:         other = other.to_hash
358:         return self if other.empty?
359:         other
360:       end
361: 
362:       @options = @options.merge(other_options).freeze
363:       assert_valid_options(@options)
364: 
365:       normalize = DataMapper::Ext::Hash.only(other_options, *OPTIONS - [ :conditions ]).map do |attribute, value|
366:         instance_variable_set("@#{attribute}", DataMapper::Ext.try_dup(value))
367:         attribute
368:       end
369: 
370:       merge_conditions([ DataMapper::Ext::Hash.except(other_options, *OPTIONS), other_options[:conditions] ])
371:       normalize_options(normalize | [ :links, :unique ])
372: 
373:       self
374:     end
valid?() click to toggle source

Indicates if the Query is valid

@return [Boolean]

  true if the query is valid

@api semipublic

     # File lib/dm-core/query.rb, line 292
292:     def valid?
293:       conditions.valid?
294:     end
|(other) click to toggle source
Alias for: union

Private Instance Methods

add_condition(condition) click to toggle source

Add a condition to the Query

@param [AbstractOperation, AbstractComparison]

  the condition to add to the Query

@return [undefined]

@api private

      # File lib/dm-core/query.rb, line 1240
1240:     def add_condition(condition)
1241:       @conditions = Conditions::Operation.new(:and) if @conditions.nil?
1242:       @conditions << condition
1243:     end
append_condition(subject, bind_value, model = self.model, operator = :eql) click to toggle source

Append conditions to this Query

  TODO: needs example

@param [Property, Symbol, String, Operator, Associations::Relationship, Path] subject

  the subject to match

@param [Object] bind_value

  the value to match on

@param [Symbol] operator

  the operator to match with

@return [Query::Conditions::AbstractOperation]

  the Query conditions

@api private

      # File lib/dm-core/query.rb, line 1146
1146:     def append_condition(subject, bind_value, model = self.model, operator = :eql)
1147:       case subject
1148:         when Property, Associations::Relationship then append_property_condition(subject, bind_value, operator)
1149:         when Symbol                               then append_symbol_condition(subject, bind_value, model, operator)
1150:         when String                               then append_string_condition(subject, bind_value, model, operator)
1151:         when Operator                             then append_operator_conditions(subject, bind_value, model)
1152:         when Path                                 then append_path(subject, bind_value, model, operator)
1153:         else
1154:           raise ArgumentError, "#{subject} is an invalid instance: #{subject.class}"
1155:       end
1156:     end
append_operator_conditions(operator, bind_value, model) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1218
1218:     def append_operator_conditions(operator, bind_value, model)
1219:       append_condition(operator.target, bind_value, model, operator.operator)
1220:     end
append_path(path, bind_value, model, operator) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1223
1223:     def append_path(path, bind_value, model, operator)
1224:       path.relationships.each do |relationship|
1225:         inverse = relationship.inverse
1226:         @links.unshift(inverse) unless @links.include?(inverse)
1227:       end
1228: 
1229:       append_condition(path.property, bind_value, path.model, operator)
1230:     end
append_property_condition(subject, bind_value, operator) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1169
1169:     def append_property_condition(subject, bind_value, operator)
1170:       negated = operator == :not
1171: 
1172:       if operator == :eql || negated
1173:         # transform :relationship => nil into :relationship.not => association
1174:         if subject.respond_to?(:collection_for) && bind_value.nil?
1175:           negated    = !negated
1176:           bind_value = collection_for_nil(subject)
1177:         end
1178: 
1179:         operator = equality_operator_for_type(bind_value)
1180:       end
1181: 
1182:       condition = Conditions::Comparison.new(operator, subject, bind_value)
1183: 
1184:       if negated
1185:         condition = Conditions::Operation.new(:not, condition)
1186:       end
1187: 
1188:       add_condition(condition)
1189:     end
append_string_condition(string, bind_value, model, operator) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1197
1197:     def append_string_condition(string, bind_value, model, operator)
1198:       if string.include?('.')
1199:         query_path = model
1200: 
1201:         target_components = string.split('.')
1202:         last_component    = target_components.last
1203:         operator          = target_components.pop.to_sym if DataMapper::Query::Conditions::Comparison.slugs.any? { |slug| slug.to_s == last_component }
1204: 
1205:         target_components.each { |method| query_path = query_path.send(method) }
1206: 
1207:         append_condition(query_path, bind_value, model, operator)
1208:       else
1209:         repository_name = repository.name
1210:         subject         = model.properties(repository_name)[string] ||
1211:                           model.relationships(repository_name)[string]
1212: 
1213:         append_condition(subject, bind_value, model, operator)
1214:       end
1215:     end
append_symbol_condition(symbol, bind_value, model, operator) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1192
1192:     def append_symbol_condition(symbol, bind_value, model, operator)
1193:       append_condition(symbol.to_s, bind_value, model, operator)
1194:     end
assert_valid_boolean(name, value) click to toggle source

Used to verify value of boolean properties in conditions @api private

     # File lib/dm-core/query.rb, line 975
975:     def assert_valid_boolean(name, value)
976:       if value != true && value != false
977:         raise ArgumentError, "+#{name}+ should be true or false, but was #{value.inspect}"
978:       end
979:     end
assert_valid_conditions(conditions) click to toggle source

Verifies that value of :conditions option refers to existing properties

@api private

     # File lib/dm-core/query.rb, line 848
848:     def assert_valid_conditions(conditions)
849:       assert_kind_of 'options[:conditions]', conditions, Conditions::AbstractOperation, Conditions::AbstractComparison, Hash, Array
850: 
851:       case conditions
852:         when Hash
853:           conditions.each do |subject, bind_value|
854:             case subject
855:               when Symbol, ::String
856:                 original = subject
857:                 subject  = subject.to_s
858:                 name     = subject[0, subject.index('.') || subject.length]
859: 
860:                 unless @properties.named?(name) || @relationships.named?(name)
861:                   raise ArgumentError, "condition #{original.inspect} does not map to a property or relationship in #{model}"
862:                 end
863: 
864:               when Property
865:                 unless @properties.include?(subject)
866:                   raise ArgumentError, "condition #{subject.name.inspect} does not map to a property in #{model}, but belongs to #{subject.model}"
867:                 end
868: 
869:               when Operator
870:                 operator = subject.operator
871: 
872:                 unless Conditions::Comparison.slugs.include?(operator) || operator == :not
873:                   raise ArgumentError, "condition #{subject.inspect} used an invalid operator #{operator}"
874:                 end
875: 
876:                 assert_valid_conditions(subject.target => bind_value)
877: 
878:               when Path
879:                 assert_valid_links(subject.relationships)
880: 
881:               when Associations::Relationship
882:                 # TODO: validate that it belongs to the current model
883:                 #unless subject.source_model.equal?(model)
884:                 #  raise ArgumentError, "condition #{subject.name.inspect} is not a valid relationship for #{model}, it's source model was #{subject.source_model}"
885:                 #end
886: 
887:               else
888:                 raise ArgumentError, "condition #{subject.inspect} of an unsupported object #{subject.class}"
889:             end
890:           end
891: 
892:         when Array
893:           if conditions.empty?
894:             raise ArgumentError, '+options[:conditions]+ should not be empty'
895:           end
896: 
897:           first_condition = conditions.first
898: 
899:           unless first_condition.kind_of?(String) && !DataMapper::Ext.blank?(first_condition)
900:             raise ArgumentError, '+options[:conditions]+ should have a statement for the first entry'
901:           end
902:       end
903:     end
assert_valid_fields(fields, unique) click to toggle source

Verifies that value of :fields option refers to existing properties

@api private

     # File lib/dm-core/query.rb, line 785
785:     def assert_valid_fields(fields, unique)
786:       fields = fields.to_ary
787: 
788:       model = self.model
789: 
790:       valid_properties = model.properties
791: 
792:       model.descendants.each do |descendant|
793:         valid_properties += descendant.properties
794:       end
795: 
796:       fields.each do |field|
797:         case field
798:           when Symbol, String
799:             unless valid_properties.named?(field)
800:               raise ArgumentError, "+options[:fields]+ entry #{field.inspect} does not map to a property in #{model}"
801:             end
802: 
803:           when Property
804:             unless valid_properties.include?(field)
805:               raise ArgumentError, "+options[:field]+ entry #{field.name.inspect} does not map to a property in #{model}"
806:             end
807: 
808:           else
809:             raise ArgumentError, "+options[:fields]+ entry #{field.inspect} of an unsupported object #{field.class}"
810:         end
811:       end
812:     end
assert_valid_limit(limit) click to toggle source

Verifies the limit is equal to or greater than 0

@raise [ArgumentError]

  raised if the limit is not an Integer or less than 0

@api private

     # File lib/dm-core/query.rb, line 925
925:     def assert_valid_limit(limit)
926:       limit = limit.to_int
927: 
928:       unless limit >= 0
929:         raise ArgumentError, "+options[:limit]+ must be greater than or equal to 0, but was #{limit.inspect}"
930:       end
931:     end
assert_valid_offset(offset, limit) click to toggle source

Verifies that query offset is non-negative and only used together with limit @api private

     # File lib/dm-core/query.rb, line 907
907:     def assert_valid_offset(offset, limit)
908:       offset = offset.to_int
909: 
910:       unless offset >= 0
911:         raise ArgumentError, "+options[:offset]+ must be greater than or equal to 0, but was #{offset.inspect}"
912:       end
913: 
914:       if offset > 0 && limit.nil?
915:         raise ArgumentError, '+options[:offset]+ cannot be greater than 0 if limit is not specified'
916:       end
917:     end
assert_valid_options(options) click to toggle source

Validate the options

@param [#] options

  the options to validate

@raise [ArgumentError]

  if any pairs in +options+ are invalid options

@api private

     # File lib/dm-core/query.rb, line 763
763:     def assert_valid_options(options)
764:       options = options.to_hash
765: 
766:       options.each do |attribute, value|
767:         case attribute
768:           when :fields                         then assert_valid_fields(value, options[:unique])
769:           when :links                          then assert_valid_links(value)
770:           when :conditions                     then assert_valid_conditions(value)
771:           when :offset                         then assert_valid_offset(value, options[:limit])
772:           when :limit                          then assert_valid_limit(value)
773:           when :order                          then assert_valid_order(value, options[:fields])
774:           when :unique, :add_reversed, :reload then assert_valid_boolean("options[:#{attribute}]", value)
775:           else
776:             assert_valid_conditions(attribute => value)
777:         end
778:       end
779:     end
assert_valid_order(order, fields) click to toggle source

Verifies that :order option uses proper operator and refers to existing property

@api private

     # File lib/dm-core/query.rb, line 937
937:     def assert_valid_order(order, fields)
938:       return if order.nil?
939: 
940:       order = Array(order)
941:       if order.empty? && fields && fields.any? { |property| !property.kind_of?(Operator) }
942:         raise ArgumentError, '+options[:order]+ should not be empty if +options[:fields] contains a non-operator'
943:       end
944: 
945:       model = self.model
946: 
947:       order.each do |order_entry|
948:         case order_entry
949:           when Symbol, String
950:             unless @properties.named?(order_entry)
951:               raise ArgumentError, "+options[:order]+ entry #{order_entry.inspect} does not map to a property in #{model}"
952:             end
953: 
954:           when Property, Path
955:             # Allow any arbitrary property, since it may map to a model
956:             # that has been included via the :links option
957: 
958:           when Operator, Direction
959:             operator = order_entry.operator
960: 
961:             unless operator == :asc || operator == :desc
962:               raise ArgumentError, "+options[:order]+ entry #{order_entry.inspect} used an invalid operator #{operator}"
963:             end
964: 
965:             assert_valid_order([ order_entry.target ], fields)
966: 
967:           else
968:             raise ArgumentError, "+options[:order]+ entry #{order_entry.inspect} of an unsupported object #{order_entry.class}"
969:         end
970:       end
971:     end
assert_valid_other(other) click to toggle source

Verifies that associations given in conditions belong to the same repository as query’s model

@api private

      # File lib/dm-core/query.rb, line 985
 985:     def assert_valid_other(other)
 986:       other_repository = other.repository
 987:       repository       = self.repository
 988:       other_class      = other.class
 989: 
 990:       unless other_repository == repository
 991:         raise ArgumentError, "+other+ #{other_class} must be for the #{repository.name} repository, not #{other_repository.name}"
 992:       end
 993: 
 994:       other_model = other.model
 995:       model       = self.model
 996: 
 997:       unless other_model >= model
 998:         raise ArgumentError, "+other+ #{other_class} must be for the #{model.name} model, not #{other_model.name}"
 999:       end
1000:     end
collection_for_nil(relationship) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1316
1316:     def collection_for_nil(relationship)
1317:       query = relationship.query.dup
1318: 
1319:       relationship.target_key.each do |target_key|
1320:         query[target_key.name.not] = nil if target_key.allow_nil?
1321:       end
1322: 
1323:       relationship.target_model.all(query)
1324:     end
each_comparison() click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1327
1327:     def each_comparison
1328:       operands = conditions.operands.to_a
1329: 
1330:       while operand = operands.shift
1331:         if operand.respond_to?(:operands)
1332:           operands.unshift(*operand.operands)
1333:         else
1334:           yield operand
1335:         end
1336:       end
1337:     end
equality_operator_for_type(bind_value) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1159
1159:     def equality_operator_for_type(bind_value)
1160:       case bind_value
1161:         when Model, String then :eql
1162:         when Enumerable    then :in
1163:         when Regexp        then :regexp
1164:         else                    :eql
1165:       end
1166:     end
extract_offset_limit_from_integer(integer) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1279
1279:     def extract_offset_limit_from_integer(integer)
1280:       [ integer, 1 ]
1281:     end
extract_offset_limit_from_one_argument(arg) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1271
1271:     def extract_offset_limit_from_one_argument(arg)
1272:       case arg
1273:         when Integer then extract_offset_limit_from_integer(arg)
1274:         when Range   then extract_offset_limit_from_range(arg)
1275:       end
1276:     end
extract_offset_limit_from_range(range) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1284
1284:     def extract_offset_limit_from_range(range)
1285:       offset = range.first
1286:       limit  = range.last - offset
1287:       limit  = limit.succ unless range.exclude_end?
1288:       return offset, limit
1289:     end
extract_offset_limit_from_two_arguments(*args) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1266
1266:     def extract_offset_limit_from_two_arguments(*args)
1267:       args if args.all? { |arg| arg.kind_of?(Integer) }
1268:     end
extract_slice_arguments(*args) click to toggle source

Extract arguments for # and # then return offset and limit

@param [Integer, Array(Integer), Range] *args the offset,

  offset and limit, or range indicating first and last position

@return [Integer] the offset @return [Integer, nil] the limit, if any

@api private

      # File lib/dm-core/query.rb, line 1254
1254:     def extract_slice_arguments(*args)
1255:       offset, limit = case args.size
1256:         when 2 then extract_offset_limit_from_two_arguments(*args)
1257:         when 1 then extract_offset_limit_from_one_argument(*args)
1258:       end
1259: 
1260:       return offset, limit if offset && limit
1261: 
1262:       raise ArgumentError, "arguments may be 1 or 2 Integers, or 1 Range object, was: #{args.inspect}"
1263:     end
get_relative_position(offset, limit) click to toggle source

@api private

      # File lib/dm-core/query.rb, line 1292
1292:     def get_relative_position(offset, limit)
1293:       self_offset = self.offset
1294:       self_limit  = self.limit
1295:       new_offset  = self_offset + offset
1296: 
1297:       if limit <= 0 || (self_limit && new_offset + limit > self_offset + self_limit)
1298:         raise RangeError, "offset #{offset} and limit #{limit} are outside allowed range"
1299:       end
1300: 
1301:       return new_offset, limit
1302:     end
initialize_copy(*) click to toggle source

Copying contructor, called for Query#dup

@api semipublic

     # File lib/dm-core/query.rb, line 747
747:     def initialize_copy(*)
748:       @fields     = @fields.dup
749:       @links      = @links.dup
750:       @conditions = @conditions.dup
751:       @order      = DataMapper::Ext.try_dup(@order)
752:     end
merge_conditions(conditions) click to toggle source

Handle all the conditions options provided

@param [Array<Conditions::AbstractOperation, Conditions::AbstractComparison, Hash, Array>]

  a list of conditions

@return [undefined]

@api private

      # File lib/dm-core/query.rb, line 1010
1010:     def merge_conditions(conditions)
1011:       @conditions = Conditions::Operation.new(:and) << @conditions unless @conditions.nil?
1012: 
1013:       conditions.compact!
1014:       conditions.each do |condition|
1015:         case condition
1016:           when Conditions::AbstractOperation, Conditions::AbstractComparison
1017:             add_condition(condition)
1018: 
1019:           when Hash
1020:             condition.each { |kv| append_condition(*kv) }
1021: 
1022:           when Array
1023:             statement, *bind_values = *condition
1024:             raw_condition = [ statement ]
1025:             raw_condition << bind_values if bind_values.size > 0
1026:             add_condition(raw_condition)
1027:             @raw = true
1028:         end
1029:       end
1030:     end
model_key() click to toggle source

Return the model key

@return [PropertySet]

  the model key

@api private

      # File lib/dm-core/query.rb, line 1440
1440:     def model_key
1441:       @properties.key
1442:     end
normalize_fields() click to toggle source

Normalize fields to Property instances

@api private

      # File lib/dm-core/query.rb, line 1081
1081:     def normalize_fields
1082:       @fields = @fields.map do |field|
1083:         case field
1084:           when Symbol, String
1085:             @properties[field]
1086: 
1087:           when Property, Operator
1088:             field
1089:         end
1090:       end
1091:     end
normalize_options(options = OPTIONS) click to toggle source

Normalize options

@param [Array] options

  the options to normalize

@return [undefined]

@api private

      # File lib/dm-core/query.rb, line 1040
1040:     def normalize_options(options = OPTIONS)
1041:       normalize_order  if options.include? :order
1042:       normalize_fields if options.include? :fields
1043:       normalize_links  if options.include? :links
1044:       normalize_unique if options.include? :unique
1045:     end
normalize_order() click to toggle source

Normalize order elements to Query::Direction instances

@api private

      # File lib/dm-core/query.rb, line 1050
1050:     def normalize_order
1051:       return if @order.nil?
1052: 
1053:       @order = Array(@order)
1054:       @order = @order.map do |order|
1055:         case order
1056:           when Operator
1057:             target   = order.target
1058:             property = target.kind_of?(Property) ? target : @properties[target]
1059: 
1060:             Direction.new(property, order.operator)
1061: 
1062:           when Symbol, String
1063:             Direction.new(@properties[order])
1064: 
1065:           when Property
1066:             Direction.new(order)
1067: 
1068:           when Direction
1069:             order.dup
1070: 
1071:           when Path
1072:             Direction.new(order.property)
1073: 
1074:         end
1075:       end
1076:     end
normalize_unique() click to toggle source

Normalize the unique attribute

If any links are present, and the unique attribute was not explicitly specified, then make sure the query is marked as unique

@api private

      # File lib/dm-core/query.rb, line 1127
1127:     def normalize_unique
1128:       @unique = links.any? unless @options.key?(:unique)
1129:     end
other_conditions(other, operation) click to toggle source

Return the union with another query’s conditions

@param [Query] other

  the query conditions to union with

@return [OrOperation]

  the union of the query conditions and other conditions

@api private

      # File lib/dm-core/query.rb, line 1366
1366:     def other_conditions(other, operation)
1367:       self_conditions = query_conditions(self)
1368: 
1369:       unless self_conditions.kind_of?(Conditions::Operation)
1370:         operation_slug = case operation
1371:                          when :intersection, :difference then :and
1372:                          when :union                     then :or
1373:                          end
1374: 
1375:         self_conditions = Conditions::Operation.new(operation_slug, self_conditions)
1376:       end
1377: 
1378:       self_conditions.send(operation, query_conditions(other))
1379:     end
query_conditions(query) click to toggle source

Extract conditions from a Query

@param [Query] query

  the query with conditions

@return [AbstractOperation]

  the operation

@api private

      # File lib/dm-core/query.rb, line 1390
1390:     def query_conditions(query)
1391:       if query.limit || query.links.any?
1392:         query.to_subquery
1393:       else
1394:         query.conditions
1395:       end
1396:     end
record_value(record, property) click to toggle source

TODO: DRY this up with conditions @api private

      # File lib/dm-core/query.rb, line 1306
1306:     def record_value(record, property)
1307:       case record
1308:         when Hash
1309:           record.fetch(property, record[property.field])
1310:         when Resource
1311:           property.get!(record)
1312:       end
1313:     end
self_relationship() click to toggle source

Return a self referrential relationship

@return [Associations::OneToMany::Relationship]

  the 1:m association to the same model

@api private

      # File lib/dm-core/query.rb, line 1404
1404:     def self_relationship
1405:       @self_relationship ||=
1406:         begin
1407:           model = self.model
1408:           Associations::OneToMany::Relationship.new(
1409:             :self,
1410:             model,
1411:             model,
1412:             self_relationship_options
1413:           )
1414:         end
1415:     end
self_relationship_options() click to toggle source

Return options for the self referrential relationship

@return [Hash]

  the options to use with the self referrential relationship

@api private

      # File lib/dm-core/query.rb, line 1423
1423:     def self_relationship_options
1424:       keys       = model_key.map { |property| property.name }
1425:       repository = self.repository
1426:       {
1427:         :child_key              => keys,
1428:         :parent_key             => keys,
1429:         :child_repository_name  => repository.name,
1430:         :parent_repository_name => repository.name,
1431:       }
1432:     end
set_operation(operation, other) click to toggle source

Apply a set operation on self and another query

@param [Symbol] operation

  the set operation to apply

@param [Query] other

  the other query to apply the set operation on

@return [Query]

  the query that was created for the set operation

@api private

      # File lib/dm-core/query.rb, line 1350
1350:     def set_operation(operation, other)
1351:       assert_valid_other(other)
1352:       query = self.class.new(@repository, @model, other.to_relative_hash)
1353:       query.instance_variable_set(:@conditions, other_conditions(other, operation))
1354:       query
1355:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.