Class: DataMapper::Query
- Inherits:
-
Object
- Object
- DataMapper::Query
- Extended by:
- Equalizer
- Includes:
- Assertions
- Defined in:
- lib/dm-core/query.rb,
lib/dm-core/query/path.rb,
lib/dm-core/query/sort.rb,
lib/dm-core/query/operator.rb,
lib/dm-core/query/direction.rb,
lib/dm-core/query/conditions/operation.rb,
lib/dm-core/query/conditions/comparison.rb
Overview
Query class represents a query which will be run against the data-store. Generally Query objects can be found inside Collection objects.
Defined Under Namespace
Modules: Conditions Classes: Direction, Operator, Path, Sort
Constant Summary collapse
- OPTIONS =
[ :fields, :links, :conditions, :offset, :limit, :order, :unique, :add_reversed, :reload ].to_set.freeze
Instance Attribute Summary collapse
-
#conditions ⇒ Array
readonly
Returns the conditions of the query.
-
#fields ⇒ PropertySet
readonly
Returns the fields.
-
#limit ⇒ Integer?
readonly
Returns the limit query uses.
-
#links ⇒ Array<DataMapper::Associations::Relationship>
readonly
private
Returns the links (associations) query fetches.
-
#model ⇒ Model
readonly
Returns model (class) that is used to instantiate objects from query result returned by adapter.
-
#offset ⇒ Integer
readonly
Returns the offset query uses.
-
#options ⇒ Hash
readonly
private
Returns the original options.
-
#order ⇒ Array
readonly
Returns the order.
-
#repository ⇒ Repository
readonly
Returns the repository query should be executed in.
Class Method Summary collapse
-
.target_conditions(source, source_key, target_key) ⇒ AbstractComparison, AbstractOperation
private
Extract conditions to match a Resource or Collection.
-
.target_query(repository, model, source) ⇒ Query
private
The query to match the resources with.
Instance Method Summary collapse
-
#add_reversed? ⇒ Boolean
private
Indicates if each result should be returned in reverse order.
-
#clear ⇒ self
Clear conditions.
-
#condition_properties ⇒ Set<Property>
private
Get the properties used in the conditions.
-
#difference(other) ⇒ Query
(also: #-)
Return the difference with another query.
-
#filter_records(records) ⇒ Enumerable
Takes an Enumerable of records, and destructively filters it.
-
#inspect ⇒ String
Returns detailed human readable string representation of the query.
-
#intersection(other) ⇒ Query
(also: #&)
Return the intersection with another query.
-
#limit_records(records) ⇒ Enumerable
Limits a set of records by the offset and/or limit.
-
#match_records(records) ⇒ Enumerable
Filter a set of records by the conditions.
-
#merge(other) ⇒ Query
Similar to Query#update, but acts on a duplicate.
-
#raw? ⇒ Boolean
Indicates if the Query has raw conditions.
-
#relative(options) ⇒ Object
Builds and returns new query that merges original with one given, and slices the result with respect to :limit and :offset options.
-
#reload? ⇒ Boolean
Indicates if the Query results should replace the results in the Identity Map.
-
#reverse ⇒ Query
Returns a new Query with a reversed order.
-
#reverse! ⇒ Query
Reverses the sort order of the Query.
-
#slice(*args) ⇒ Object
(also: #[])
Slices collection by adding limit and offset to the query, so a single query is executed.
-
#slice!(*args) ⇒ Object
Slices collection by adding limit and offset to the query, so a single query is executed.
-
#sort_records(records) ⇒ Enumerable
Sorts a list of Records by the order.
-
#sorted_fields ⇒ Array<Property>
private
Return a list of fields in predictable order.
-
#to_hash ⇒ Hash
private
Hash representation of a Query.
-
#to_relative_hash ⇒ Hash
private
Extract options from a Query.
-
#to_subquery ⇒ AndOperation
private
Transform Query into subquery conditions.
-
#union(other) ⇒ Query
(also: #|, #+)
Return the union with another query.
-
#unique? ⇒ Boolean
Indicates if the Query results should be unique.
-
#update(other) ⇒ Query
Updates the Query with another Query or conditions.
-
#valid? ⇒ Boolean
Indicates if the Query is valid.
Methods included from Equalizer
Methods included from Assertions
Instance Attribute Details
#conditions ⇒ Array (readonly)
Returns the conditions of the query
In the following example:
Conditions are “greater than” operator for “wins” field and exact match operator for “conference”.
178 179 180 |
# File 'lib/dm-core/query.rb', line 178 def conditions @conditions end |
#fields ⇒ PropertySet (readonly)
Returns the fields
Set in cases like the following:
153 154 155 |
# File 'lib/dm-core/query.rb', line 153 def fields @fields end |
#limit ⇒ Integer? (readonly)
Returns the limit query uses
Set in cases like the following:
206 207 208 |
# File 'lib/dm-core/query.rb', line 206 def limit @limit end |
#links ⇒ Array<DataMapper::Associations::Relationship> (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the links (associations) query fetches
161 162 163 |
# File 'lib/dm-core/query.rb', line 161 def links @links end |
#model ⇒ Model (readonly)
Returns model (class) that is used to instantiate objects from query result returned by adapter
139 140 141 |
# File 'lib/dm-core/query.rb', line 139 def model @model end |
#offset ⇒ Integer (readonly)
Returns the offset query uses
Set in cases like the following:
192 193 194 |
# File 'lib/dm-core/query.rb', line 192 def offset @offset end |
#options ⇒ Hash (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the original options
231 232 233 |
# File 'lib/dm-core/query.rb', line 231 def @options end |
#order ⇒ Array (readonly)
Returns the order
Set in cases like the following:
query order is a set of two ordering rules, descending on “created_at” field and descending again on “length” field
223 224 225 |
# File 'lib/dm-core/query.rb', line 223 def order @order end |
#repository ⇒ Repository (readonly)
Returns the repository query should be executed in
Set in cases like the following:
129 130 131 |
# File 'lib/dm-core/query.rb', line 129 def repository @repository end |
Class Method Details
.target_conditions(source, source_key, target_key) ⇒ AbstractComparison, AbstractOperation
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Extract conditions to match a Resource or Collection
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/dm-core/query.rb', line 49 def self.target_conditions(source, source_key, target_key) target_key_size = target_key.size source_values = [] if source.nil? source_values << [ nil ] * target_key_size else Array(source).each do |resource| next unless source_key.loaded?(resource) source_value = source_key.get!(resource) next unless target_key.valid?(source_value) source_values << source_value end end source_values.uniq! if target_key_size == 1 target_key = target_key.first source_values.flatten! if source_values.size == 1 Conditions::EqualToComparison.new(target_key, source_values.first) else Conditions::InclusionComparison.new(target_key, source_values) end else or_operation = Conditions::OrOperation.new source_values.each do |source_value| and_operation = Conditions::AndOperation.new target_key.zip(source_value) do |property, value| and_operation << Conditions::EqualToComparison.new(property, value) end or_operation << and_operation end or_operation end end |
.target_query(repository, model, source) ⇒ Query
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the query to match the resources with.
103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/dm-core/query.rb', line 103 def self.target_query(repository, model, source) if source.respond_to?(:query) source.query elsif source.kind_of?(Enumerable) key = model.key(repository.name) conditions = Query.target_conditions(source, key, key) repository.new_query(model, :conditions => conditions) else raise ArgumentError, "+source+ must respond to #query or be an Enumerable, but was #{source.class}" end end |
Instance Method Details
#add_reversed? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Indicates if each result should be returned in reverse order
Set in cases like the following:
Note that :add_reversed option may be used in conditions directly, but this is rarely the case
248 249 250 |
# File 'lib/dm-core/query.rb', line 248 def add_reversed? @add_reversed end |
#clear ⇒ self
Clear conditions
472 473 474 475 |
# File 'lib/dm-core/query.rb', line 472 def clear @conditions = Conditions::Operation.new(:null) self end |
#condition_properties ⇒ Set<Property>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Get the properties used in the conditions
627 628 629 630 631 632 633 634 635 636 637 |
# File 'lib/dm-core/query.rb', line 627 def condition_properties properties = Set.new each_comparison do |comparison| next unless comparison.respond_to?(:subject) subject = comparison.subject properties << subject if subject.kind_of?(Property) end properties end |
#difference(other) ⇒ Query Also known as: -
Return the difference with another query
461 462 463 |
# File 'lib/dm-core/query.rb', line 461 def difference(other) set_operation(:difference, other) end |
#filter_records(records) ⇒ Enumerable
Takes an Enumerable of records, and destructively filters it. First finds all matching conditions, then sorts it, then does offset & limit
488 489 490 491 492 493 494 |
# File 'lib/dm-core/query.rb', line 488 def filter_records(records) records = records.uniq if unique? records = match_records(records) if conditions records = sort_records(records) if order records = limit_records(records) if limit || offset > 0 records end |
#inspect ⇒ String
Returns detailed human readable string representation of the query
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
# File 'lib/dm-core/query.rb', line 604 def inspect attrs = [ [ :repository, repository.name ], [ :model, model ], [ :fields, fields ], [ :links, links ], [ :conditions, conditions ], [ :order, order ], [ :limit, limit ], [ :offset, offset ], [ :reload, reload? ], [ :unique, unique? ], ] "#<#{self.class.name} #{attrs.map { |key, value| "@#{key}=#{value.inspect}" }.join(' ')}>" end |
#intersection(other) ⇒ Query Also known as: &
Return the intersection with another query
445 446 447 448 |
# File 'lib/dm-core/query.rb', line 445 def intersection(other) return dup if self == other set_operation(:intersection, other) end |
#limit_records(records) ⇒ Enumerable
Limits a set of records by the offset and/or limit
538 539 540 541 542 543 544 545 546 547 548 549 550 |
# File 'lib/dm-core/query.rb', line 538 def limit_records(records) offset = self.offset limit = self.limit size = records.size if offset > size - 1 [] elsif (limit && limit != size) || offset > 0 records[offset, limit || size] || [] else records.dup end end |
#match_records(records) ⇒ Enumerable
Filter a set of records by the conditions
505 506 507 508 |
# File 'lib/dm-core/query.rb', line 505 def match_records(records) conditions = self.conditions records.select { |record| conditions.matches?(record) } end |
#merge(other) ⇒ Query
Similar to Query#update, but acts on a duplicate.
385 386 387 |
# File 'lib/dm-core/query.rb', line 385 def merge(other) dup.update(other) end |
#raw? ⇒ Boolean
Indicates if the Query has raw conditions
282 283 284 |
# File 'lib/dm-core/query.rb', line 282 def raw? @raw end |
#relative(options) ⇒ Object
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:
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/dm-core/query.rb', line 402 def relative() = .to_hash offset = nil limit = self.limit if .key?(:offset) && (.key?(:limit) || limit) = .dup offset = .delete(:offset) limit = .delete(:limit) || limit - offset end query = merge() query = query.slice!(offset, limit) if offset query end |
#reload? ⇒ Boolean
Indicates if the Query results should replace the results in the Identity Map
TODO: needs example
260 261 262 |
# File 'lib/dm-core/query.rb', line 260 def reload? @reload end |
#reverse ⇒ Query
Returns a new Query with a reversed order
Will execute a single query with correct order
308 309 310 |
# File 'lib/dm-core/query.rb', line 308 def reverse dup.reverse! end |
#reverse! ⇒ Query
Reverses the sort order of the Query
Will execute a single query with original order and then reverse collection in the Ruby space
325 326 327 328 329 330 331 332 333 |
# File 'lib/dm-core/query.rb', line 325 def reverse! # reverse the sort order @order.map! { |direction| direction.dup.reverse! } # copy the order to the options @options = @options.merge(:order => @order).freeze self end |
#slice(*args) ⇒ Object Also known as: []
Slices collection by adding limit and offset to the query, so a single query is executed
will execute query with the following limit and offset (when repository uses DataObjects adapter, and thus queries use SQL):
LIMIT 5 OFFSET 3
566 567 568 |
# File 'lib/dm-core/query.rb', line 566 def slice(*args) dup.slice!(*args) end |
#slice!(*args) ⇒ Object
Slices collection by adding limit and offset to the query, so a single query is executed
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
588 589 590 591 592 593 594 595 596 |
# File 'lib/dm-core/query.rb', line 588 def slice!(*args) offset, limit = extract_slice_arguments(*args) if self.limit || self.offset > 0 offset, limit = get_relative_position(offset, limit) end update(:offset => offset, :limit => limit) end |
#sort_records(records) ⇒ Enumerable
Sorts a list of Records by the order
519 520 521 522 523 524 525 526 527 |
# File 'lib/dm-core/query.rb', line 519 def sort_records(records) sort_order = order.map { |direction| [ direction.target, direction.operator == :asc ] } records.sort_by do |record| sort_order.map do |(property, ascending)| Sort.new(record_value(record, property), ascending) end end end |
#sorted_fields ⇒ Array<Property>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Return a list of fields in predictable order
645 646 647 |
# File 'lib/dm-core/query.rb', line 645 def sorted_fields fields.sort_by { |property| property.hash } end |
#to_hash ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Hash representation of a Query
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 |
# File 'lib/dm-core/query.rb', line 666 def to_hash { :repository => repository.name, :model => model.name, :fields => fields, :links => links, :conditions => conditions, :offset => offset, :limit => limit, :order => order, :unique => unique?, :add_reversed => add_reversed?, :reload => reload?, } end |
#to_relative_hash ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Extract options from a Query
691 692 693 |
# File 'lib/dm-core/query.rb', line 691 def to_relative_hash DataMapper::Ext::Hash.only(to_hash, :fields, :order, :unique, :add_reversed, :reload) end |
#to_subquery ⇒ AndOperation
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Transform Query into subquery conditions
655 656 657 658 |
# File 'lib/dm-core/query.rb', line 655 def to_subquery collection = model.all(merge(:fields => model_key)) Conditions::Operation.new(:and, Conditions::Comparison.new(:in, self_relationship, collection)) end |
#union(other) ⇒ Query Also known as: |, +
Return the union with another query
428 429 430 431 |
# File 'lib/dm-core/query.rb', line 428 def union(other) return dup if self == other set_operation(:union, other) end |
#unique? ⇒ Boolean
Indicates if the Query results should be unique
TODO: needs example
272 273 274 |
# File 'lib/dm-core/query.rb', line 272 def unique? @unique end |
#update(other) ⇒ Query
Updates the Query with another Query or conditions
Pretty unrealistic example:
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/dm-core/query.rb', line 351 def update(other) = if kind_of?(other.class) return self if self.eql?(other) assert_valid_other(other) other. else other = other.to_hash return self if other.empty? other end @options = @options.merge().freeze (@options) normalize = DataMapper::Ext::Hash.only(, *OPTIONS - [ :conditions ]).map do |attribute, value| instance_variable_set("@#{attribute}", DataMapper::Ext.try_dup(value)) attribute end merge_conditions([ DataMapper::Ext::Hash.except(, *OPTIONS), [:conditions] ]) (normalize | [ :links, :unique ]) self end |
#valid? ⇒ Boolean
Indicates if the Query is valid
292 293 294 |
# File 'lib/dm-core/query.rb', line 292 def valid? conditions.valid? end |