Module: ROM::SQL::Relation::Reading
- Included in:
- ROM::SQL::Relation
- Defined in:
- lib/rom/sql/relation/reading.rb
Overview
Query API for SQL::Relation
Constant Summary collapse
- ROW_LOCK_MODES =
Row-level lock modes
Hash.new(update: 'FOR UPDATE'.freeze).update( # https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE postgres: { update: 'FOR UPDATE'.freeze, no_key_update: 'FOR NO KEY UPDATE'.freeze, share: 'FOR SHARE'.freeze, key_share: 'FOR KEY SHARE'.freeze }, # https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html mysql: { update: 'FOR UPDATE'.freeze, share: 'LOCK IN SHARE MODE'.freeze } ).freeze
Instance Method Summary collapse
-
#as_hash(attribute = primary_key) ⇒ Hash
Returns hash with all tuples being the key of each the provided attribute.
-
#avg(*args) ⇒ Object
Returns a result of SQL AVG clause.
-
#count ⇒ Relation
Return relation count.
-
#distinct(*args, &block) ⇒ Relation
Returns a copy of the relation with a SQL DISTINCT clause.
-
#each_batch(size: 1000) {|| ... } ⇒ Object
Process the dataset in batches.
-
#exclude(*args, &block) ⇒ Relation
Restrict a relation to not match criteria.
-
#exist?(*args, &block) ⇒ TrueClass, FalseClass
Checks whether a relation has at least one tuple.
-
#exists(other, condition = nil) ⇒ SQL::Relation
Restrict with rows from another relation.
-
#fetch(pk) ⇒ Relation
Fetch a tuple identified by the pk.
-
#first ⇒ Hash
Get first tuple from the relation.
-
#group(*args, &block) ⇒ Relation
Group by specific columns.
-
#group_and_count(*args, &block) ⇒ Relation
Group by specific columns and count by group.
-
#group_append(*args, &block) ⇒ Relation
Group by more columns.
-
#having(*args, &block) ⇒ Relation
Restrict a relation to match grouping criteria.
-
#invert ⇒ Relation
Inverts the current WHERE and HAVING clauses.
-
#join(*args, &block) ⇒ Relation
(also: #inner_join)
Join with another relation using INNER JOIN.
-
#last ⇒ Hash
Get last tuple from the relation.
-
#left_join(*args, &block) ⇒ Relation
Join with another relation using LEFT OUTER JOIN.
-
#limit(*args) ⇒ Relation
Limit a relation to a specific number of tuples.
-
#lock(**options, &block) ⇒ Object
Lock rows with in the specified mode.
-
#map(key = nil, &block) ⇒ Object
Map tuples from the relation.
-
#max(*args) ⇒ Object
Returns a result of SQL MAX clause.
-
#min(*args) ⇒ Object
Returns a result of SQL MIN clause.
-
#offset(num) ⇒ Relation
Set offset for the relation.
-
#order(*args, &block) ⇒ Relation
Set order for the relation.
-
#pluck(*names) ⇒ Array
Pluck values from a specific column.
-
#prefix(name = Inflector.singularize(schema.name.dataset)) ⇒ Relation
Prefix all columns in a relation.
-
#qualified(table_alias = nil) ⇒ Relation
Qualifies all columns in a relation.
-
#qualified_columns ⇒ Array<Symbol>
Return a list of qualified column names.
-
#query ⇒ SQL::Attribute
Turn a relation into a subquery.
-
#read(sql) ⇒ SQL::Relation
Return a new relation from a raw SQL string.
-
#rename(options) ⇒ Relation
Rename columns in a relation.
-
#reverse(*args, &block) ⇒ Relation
Reverse the order of the relation.
-
#right_join(*args, &block) ⇒ Relation
Join with another relation using RIGHT JOIN.
-
#select(*args, &block) ⇒ Relation
(also: #project)
Select specific columns for select clause.
-
#select_append(*args, &block) ⇒ Relation
Append specific columns to select clause.
-
#select_group(*args, &block) ⇒ Relation
Select and group by specific columns.
-
#sum(*args) ⇒ Integer
Returns a result of SQL SUM clause.
-
#unfiltered ⇒ SQL::Relation
Discard restrictions in
WHERE
andHAVING
clauses. -
#union(relation, options = EMPTY_HASH, &block) ⇒ Object
Adds a UNION clause for relation dataset using second relation dataset.
-
#unique?(criteria) ⇒ TrueClass, FalseClass
Return if a restricted relation has 0 tuples.
-
#where(*args, &block) ⇒ Relation
Restrict a relation to match criteria.
-
#wrap(*names) ⇒ Wrap
Wrap other relations using association names.
Instance Method Details
#as_hash(attribute = primary_key) ⇒ Hash
Returns hash with all tuples being the key of each the provided attribute
982 983 984 |
# File 'lib/rom/sql/relation/reading.rb', line 982 def as_hash(attribute = primary_key) dataset.as_hash(attribute) end |
#avg(*args) ⇒ Object
Returns a result of SQL AVG clause.
330 331 332 |
# File 'lib/rom/sql/relation/reading.rb', line 330 def avg(*args) dataset.__send__(__method__, *args) end |
#count ⇒ Relation
Return relation count
53 54 55 |
# File 'lib/rom/sql/relation/reading.rb', line 53 def count dataset.count end |
#distinct(*columns) ⇒ Relation #distinct(&block) ⇒ Relation
Returns a copy of the relation with a SQL DISTINCT clause.
274 275 276 |
# File 'lib/rom/sql/relation/reading.rb', line 274 def distinct(*args, &block) new(dataset.__send__(__method__, *args, &block)) end |
#each_batch(size: 1000) {|| ... } ⇒ Object
Process the dataset in batches. The method yields a relation restricted by a primary key value. This means it discards any order internally and uses the PK sort. Currently, works only with a single-column primary key.
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 |
# File 'lib/rom/sql/relation/reading.rb', line 945 def each_batch(size: 1000) pks = schema.primary_key if pks.size > 1 raise ArgumentError, 'Composite primary keys are not supported yet' end source = order(pks[0]).limit(size) rel = source loop do ids = rel.pluck(primary_key) break if ids.empty? yield(rel) break if ids.size < size rel = source.where(pks[0] > ids.last) end end |
#exclude(*args, &block) ⇒ Relation
Restrict a relation to not match criteria
384 385 386 |
# File 'lib/rom/sql/relation/reading.rb', line 384 def exclude(*args, &block) new(dataset.__send__(__method__, *args, &block)) end |
#exist?(*args, &block) ⇒ TrueClass, FalseClass
Checks whether a relation has at least one tuple
@example users.where(name: 'John').exist? # => true
users.exist?(name: 'Klaus') # => false
users.exist? { name.is('klaus') } # => false
@param [Array
839 840 841 |
# File 'lib/rom/sql/relation/reading.rb', line 839 def exist?(*args, &block) !where(*args, &block).limit(1).count.zero? end |
#exists(other, condition = nil) ⇒ SQL::Relation
Restrict with rows from another relation. Accepts only SQL relations and uses the EXISTS clause under the hood
924 925 926 927 |
# File 'lib/rom/sql/relation/reading.rb', line 924 def exists(other, condition = nil) join_condition = condition || associations[other.name].join_keys where(other.where(join_condition).dataset.exists) end |
#fetch(pk) ⇒ Relation
Fetch a tuple identified by the pk
40 41 42 |
# File 'lib/rom/sql/relation/reading.rb', line 40 def fetch(pk) by_pk(pk).one! end |
#first ⇒ Hash
Get first tuple from the relation
66 67 68 |
# File 'lib/rom/sql/relation/reading.rb', line 66 def first limit(1).to_a.first end |
#group(*columns) ⇒ Relation #group(*attributes) ⇒ Relation #group(*attributes, &block) ⇒ Relation
Group by specific columns
713 714 715 716 717 718 719 720 721 722 723 |
# File 'lib/rom/sql/relation/reading.rb', line 713 def group(*args, &block) if block if args.size > 0 group(*args).group_append(&block) else new(dataset.__send__(__method__, *schema.canonical.group(&block))) end else new(dataset.__send__(__method__, *schema.canonical.project(*args))) end end |
#group_and_count(*args, &block) ⇒ Relation
Group by specific columns and count by group
775 776 777 |
# File 'lib/rom/sql/relation/reading.rb', line 775 def group_and_count(*args, &block) new(dataset.__send__(__method__, *args, &block)) end |
#group_append(*columns) ⇒ Relation #group_append(*attributes) ⇒ Relation #group_append(*attributes, &block) ⇒ Relation
Group by more columns
752 753 754 755 756 757 758 759 760 761 762 |
# File 'lib/rom/sql/relation/reading.rb', line 752 def group_append(*args, &block) if block if args.size > 0 group_append(*args).group_append(&block) else new(dataset.group_append(*schema.canonical.group(&block))) end else new(dataset.group_append(*args)) end end |
#having(conditions) ⇒ Relation #having(&block) ⇒ Relation
Restrict a relation to match grouping criteria
421 422 423 424 425 426 427 |
# File 'lib/rom/sql/relation/reading.rb', line 421 def having(*args, &block) if block new(dataset.having(*args, *schema.canonical.restriction(&block))) else new(dataset.__send__(__method__, *args)) end end |
#invert ⇒ Relation
Inverts the current WHERE and HAVING clauses. If there is neither a WHERE or HAVING clause, adds a WHERE clause that is always false.
441 442 443 |
# File 'lib/rom/sql/relation/reading.rb', line 441 def invert new(dataset.invert) end |
#join(dataset, join_conditions) ⇒ Relation #join(dataset, join_conditions, options) ⇒ Relation #join(relation) ⇒ Relation #join(relation, &block) ⇒ Relation Also known as: inner_join
Join with another relation using INNER JOIN
581 582 583 |
# File 'lib/rom/sql/relation/reading.rb', line 581 def join(*args, &block) __join__(__method__, *args, &block) end |
#last ⇒ Hash
Get last tuple from the relation
79 80 81 |
# File 'lib/rom/sql/relation/reading.rb', line 79 def last reverse.limit(1).first end |
#left_join(dataset, left_join_conditions) ⇒ Relation #left_join(dataset, left_join_conditions, options) ⇒ Relation #left_join(relation) ⇒ Relation #join(relation, &block) ⇒ Relation
Join with another relation using LEFT OUTER JOIN
631 632 633 |
# File 'lib/rom/sql/relation/reading.rb', line 631 def left_join(*args, &block) __join__(__method__, *args, &block) end |
#limit(num) ⇒ Relation #limit(num, offset) ⇒ Relation
Limit a relation to a specific number of tuples
518 519 520 |
# File 'lib/rom/sql/relation/reading.rb', line 518 def limit(*args) new(dataset.__send__(__method__, *args)) end |
#lock(options) ⇒ SQL::Relation #lock(options) {|relation| ... } ⇒ Object
Lock rows with in the specified mode. Check out ROW_LOCK_MODES for the list of supported modes, keep in mind available lock modes heavily depend on the database type+version you're running on.
896 897 898 899 900 901 902 903 904 905 906 |
# File 'lib/rom/sql/relation/reading.rb', line 896 def lock(**, &block) clause = lock_clause(**) if block transaction do block.call(dataset.lock_style(clause).to_a) end else new(dataset.lock_style(clause)) end end |
#map(key = nil, &block) ⇒ Object
Map tuples from the relation
143 144 145 146 147 148 149 |
# File 'lib/rom/sql/relation/reading.rb', line 143 def map(key = nil, &block) if key dataset.map(key, &block) else dataset.map(&block) end end |
#max(*args) ⇒ Object
Returns a result of SQL MAX clause.
316 317 318 |
# File 'lib/rom/sql/relation/reading.rb', line 316 def max(*args) dataset.__send__(__method__, *args) end |
#min(*args) ⇒ Object
Returns a result of SQL MIN clause.
302 303 304 |
# File 'lib/rom/sql/relation/reading.rb', line 302 def min(*args) dataset.__send__(__method__, *args) end |
#offset(num) ⇒ Relation
Set offset for the relation
532 533 534 |
# File 'lib/rom/sql/relation/reading.rb', line 532 def offset(num) new(dataset.__send__(__method__, num)) end |
#order(*columns) ⇒ Relation #order(*attributes) ⇒ Relation #order(&block) ⇒ Relation
Set order for the relation
476 477 478 479 480 481 482 |
# File 'lib/rom/sql/relation/reading.rb', line 476 def order(*args, &block) if block new(dataset.order(*args, *schema.canonical.order(&block))) else new(dataset.__send__(__method__, *args, &block)) end end |
#pluck(*names) ⇒ Array
Pluck values from a specific column
164 165 166 |
# File 'lib/rom/sql/relation/reading.rb', line 164 def pluck(*names) select(*names).map(names.length == 1 ? names.first : names) end |
#prefix(name = Inflector.singularize(schema.name.dataset)) ⇒ Relation
Prefix all columns in a relation
This method is intended to be used internally within a relation object
96 97 98 |
# File 'lib/rom/sql/relation/reading.rb', line 96 def prefix(name = Inflector.singularize(schema.name.dataset)) schema.prefix(name).(self) end |
#qualified(table_alias = nil) ⇒ Relation
Qualifies all columns in a relation
This method is intended to be used internally within a relation object
111 112 113 |
# File 'lib/rom/sql/relation/reading.rb', line 111 def qualified(table_alias = nil) schema.qualified(table_alias).(self) end |
#qualified_columns ⇒ Array<Symbol>
Return a list of qualified column names
This method is intended to be used internally within a relation object
126 127 128 |
# File 'lib/rom/sql/relation/reading.rb', line 126 def qualified_columns schema.qualified.map(&:to_sql_name) end |
#query ⇒ SQL::Attribute
Turn a relation into a subquery. Can be used for selecting a column with a subquery or restricting the result set with a IN (SELECT ...) condtion.
998 999 1000 1001 1002 |
# File 'lib/rom/sql/relation/reading.rb', line 998 def query attr = schema.to_a[0] subquery = schema.project(attr).(self).dataset SQL::Attribute[attr.type].(sql_expr: subquery) end |
#read(sql) ⇒ SQL::Relation
Return a new relation from a raw SQL string
871 872 873 |
# File 'lib/rom/sql/relation/reading.rb', line 871 def read(sql) new(dataset.db[sql], schema: schema.empty) end |
#rename(options) ⇒ Relation
Rename columns in a relation
This method is intended to be used internally within a relation object
181 182 183 |
# File 'lib/rom/sql/relation/reading.rb', line 181 def rename() schema.rename().(self) end |
#reverse(*args, &block) ⇒ Relation
Reverse the order of the relation
492 493 494 |
# File 'lib/rom/sql/relation/reading.rb', line 492 def reverse(*args, &block) new(dataset.__send__(__method__, *args, &block)) end |
#right_join(dataset, right_join_conditions) ⇒ Relation #right_join(dataset, right_join_conditions, options) ⇒ Relation #right_join(relation) ⇒ Relation #join(relation, &block) ⇒ Relation
Join with another relation using RIGHT JOIN
680 681 682 |
# File 'lib/rom/sql/relation/reading.rb', line 680 def right_join(*args, &block) __join__(__method__, *args, &block) end |
#select(*columns) ⇒ Relation #select(*attributes) ⇒ Relation #select(&block) ⇒ Relation #select(*columns, &block) ⇒ Relation Also known as: project
Select specific columns for select clause
238 239 240 |
# File 'lib/rom/sql/relation/reading.rb', line 238 def select(*args, &block) schema.project(*args, &block).(self) end |
#select_append(*args, &block) ⇒ Relation
Append specific columns to select clause
250 251 252 |
# File 'lib/rom/sql/relation/reading.rb', line 250 def select_append(*args, &block) schema.merge(schema.canonical.project(*args, &block)).(self) end |
#select_group(*args, &block) ⇒ Relation
Select and group by specific columns
790 791 792 793 |
# File 'lib/rom/sql/relation/reading.rb', line 790 def select_group(*args, &block) new_schema = schema.project(*args, &block) new_schema.(self).group(*new_schema) end |
#sum(*args) ⇒ Integer
Returns a result of SQL SUM clause.
288 289 290 |
# File 'lib/rom/sql/relation/reading.rb', line 288 def sum(*args) dataset.__send__(__method__, *args) end |
#unfiltered ⇒ SQL::Relation
Discard restrictions in WHERE
and HAVING
clauses
1012 1013 1014 |
# File 'lib/rom/sql/relation/reading.rb', line 1012 def unfiltered new(dataset.__send__(__method__)) end |
#union(relation, options = EMPTY_HASH, &block) ⇒ Object
Adds a UNION clause for relation dataset using second relation dataset
@returRelation]
811 812 813 814 815 816 817 818 819 820 821 822 |
# File 'lib/rom/sql/relation/reading.rb', line 811 def union(relation, = EMPTY_HASH, &block) # We use the original relation name here if both relations have the # same name. This makes it so if the user at some point references # the relation directly by name later on things won't break in # confusing ways. same_relation = name == relation.name alias_name = same_relation ? name : "#{name.to_sym}__#{relation.name.to_sym}" opts = { alias: alias_name.to_sym, ** } new_schema = schema.qualified(opts[:alias]) new_schema.(new(dataset.__send__(__method__, relation.dataset, opts, &block))) end |
#unique?(criteria) ⇒ TrueClass, FalseClass
Return if a restricted relation has 0 tuples
857 858 859 |
# File 'lib/rom/sql/relation/reading.rb', line 857 def unique?(criteria) !exist?(criteria) end |
#where(conditions) ⇒ Relation #where(conditions, &block) ⇒ Relation #where(&block) ⇒ Relation
Restrict a relation to match criteria
362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/rom/sql/relation/reading.rb', line 362 def where(*args, &block) if block where(*args).where(schema.canonical.restriction(&block)) elsif args.size == 1 && args[0].is_a?(Hash) new(dataset.where(coerce_conditions(args[0]))) elsif !args.empty? new(dataset.where(*args)) else self end end |
#wrap(*names) ⇒ Wrap
Wrap other relations using association names
1026 1027 1028 1029 |
# File 'lib/rom/sql/relation/reading.rb', line 1026 def wrap(*names) others = names.map { |name| associations[name].wrapped } wrap_around(*others) end |