Module: ROM::SQL::Relation::Reading
- Included in:
- ROM::SQL::Relation
- Defined in:
- lib/rom/sql/relation/reading.rb
Overview
Query API for SQL::Relation
rubocop:disable Metrics/ModuleLength
Constant Summary collapse
- ROW_LOCK_MODES =
Row-level lock modes
Hash.new({ update: 'FOR UPDATE' }).update( # https://www.postgresql.org/docs/current/static/sql-select.html#SQL-FOR-UPDATE-SHARE postgres: { update: 'FOR UPDATE', no_key_update: 'FOR NO KEY UPDATE', share: 'FOR SHARE', key_share: 'FOR KEY SHARE' }, # https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html mysql: { update: 'FOR UPDATE', share: 'LOCK IN SHARE MODE' } ).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 ⇒ Relation
Returns a copy of the relation with a SQL DISTINCT clause.
-
#each_batch(size: 1000) {|| ... } ⇒ Object
Process the dataset in batches.
-
#exclude ⇒ Relation
Restrict a relation to not match criteria.
-
#exist? ⇒ 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) ⇒ Relation
Group by specific columns.
-
#group_and_count ⇒ Relation
Group by specific columns and count by group.
-
#group_append(*args) ⇒ Relation
Group by more columns.
-
#having(*args) ⇒ Relation
Restrict a relation to match grouping criteria.
-
#invert ⇒ Relation
Inverts the current WHERE and HAVING clauses.
-
#join ⇒ Relation
(also: #inner_join)
Join with another relation using INNER JOIN.
-
#last ⇒ Hash
Get last tuple from the relation.
-
#left_join ⇒ Relation
Join with another relation using LEFT OUTER JOIN.
-
#limit(*args) ⇒ Relation
Limit a relation to a specific number of tuples.
-
#lock(**options) ⇒ Object
Lock rows with in the specified mode.
-
#map(key = nil) ⇒ 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) ⇒ 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 ⇒ Relation
Reverse the order of the relation.
-
#right_join ⇒ Relation
Join with another relation using RIGHT JOIN.
-
#select ⇒ Relation
(also: #project)
Select specific columns for select clause.
-
#select_append ⇒ Relation
Append specific columns to select clause.
-
#select_group ⇒ Relation
Select and group by specific columns.
-
#sum(*args) ⇒ Integer
Returns a result of SQL SUM clause.
-
#unfiltered ⇒ SQL::Relation
Discard restrictions in ‘WHERE` and `HAVING` clauses.
-
#union(relation, options = EMPTY_HASH) ⇒ Object
Adds a UNION clause for relation dataset using second relation dataset.
-
#unique?(criteria) ⇒ TrueClass, FalseClass
Return if a restricted relation has 0 tuples.
-
#unordered ⇒ Relation
Removes ordering for the relation.
-
#where(*args) ⇒ 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
999 1000 1001 |
# File 'lib/rom/sql/relation/reading.rb', line 999 def as_hash(attribute = primary_key) dataset.as_hash(attribute) end |
#avg(*args) ⇒ Object
Returns a result of SQL AVG clause.
332 333 334 |
# File 'lib/rom/sql/relation/reading.rb', line 332 def avg(*args) dataset.__send__(__method__, *args) end |
#count ⇒ Relation
Return relation count
55 56 57 |
# File 'lib/rom/sql/relation/reading.rb', line 55 def count dataset.count end |
#distinct(*columns) ⇒ Relation #distinct(&block) ⇒ Relation
Returns a copy of the relation with a SQL DISTINCT clause.
276 277 278 |
# File 'lib/rom/sql/relation/reading.rb', line 276 def distinct(...) new(dataset.__send__(__method__, ...)) 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.
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 |
# File 'lib/rom/sql/relation/reading.rb', line 962 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 ⇒ Relation
Restrict a relation to not match criteria
386 387 388 |
# File 'lib/rom/sql/relation/reading.rb', line 386 def exclude(...) new(dataset.__send__(__method__, ...)) end |
#exist? ⇒ 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<Object>] args Optional restrictions to filter the relation
@yield An optional block filters the relation using `where DSL`
856 857 858 |
# File 'lib/rom/sql/relation/reading.rb', line 856 def exist?(...) !where(...).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
941 942 943 944 |
# File 'lib/rom/sql/relation/reading.rb', line 941 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
42 43 44 |
# File 'lib/rom/sql/relation/reading.rb', line 42 def fetch(pk) by_pk(pk).one! end |
#first ⇒ Hash
Get first tuple from the relation
68 69 70 |
# File 'lib/rom/sql/relation/reading.rb', line 68 def first limit(1).to_a.first end |
#group(*columns) ⇒ Relation #group(*attributes) ⇒ Relation #group(*attributes, &block) ⇒ Relation
Group by specific columns
727 728 729 730 731 732 733 734 735 736 737 |
# File 'lib/rom/sql/relation/reading.rb', line 727 def group(*args, &) if block_given? if args.size.positive? group(*args).group_append(&) else new(dataset.__send__(__method__, *schema.canonical.group(&))) end else new(dataset.__send__(__method__, *schema.canonical.project(*args))) end end |
#group_and_count ⇒ Relation
Group by specific columns and count by group
789 790 791 |
# File 'lib/rom/sql/relation/reading.rb', line 789 def group_and_count(...) new(dataset.__send__(__method__, ...)) end |
#group_append(*columns) ⇒ Relation #group_append(*attributes) ⇒ Relation #group_append(*attributes, &block) ⇒ Relation
Group by more columns
766 767 768 769 770 771 772 773 774 775 776 |
# File 'lib/rom/sql/relation/reading.rb', line 766 def group_append(*args, &) if block_given? if args.size.positive? group_append(*args).group_append(&) else new(dataset.group_append(*schema.canonical.group(&))) end else new(dataset.group_append(*args)) end end |
#having(conditions) ⇒ Relation #having(&block) ⇒ Relation
Restrict a relation to match grouping criteria
423 424 425 426 427 428 429 |
# File 'lib/rom/sql/relation/reading.rb', line 423 def having(*args, &) if block_given? new(dataset.having(*args, *schema.canonical.restriction(&))) 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.
443 444 445 |
# File 'lib/rom/sql/relation/reading.rb', line 443 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
595 596 597 |
# File 'lib/rom/sql/relation/reading.rb', line 595 def join(...) __join__(__method__, ...) end |
#last ⇒ Hash
Get last tuple from the relation
81 82 83 |
# File 'lib/rom/sql/relation/reading.rb', line 81 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
645 646 647 |
# File 'lib/rom/sql/relation/reading.rb', line 645 def left_join(...) __join__(__method__, ...) end |
#limit(num) ⇒ Relation #limit(num, offset) ⇒ Relation
Limit a relation to a specific number of tuples
532 533 534 |
# File 'lib/rom/sql/relation/reading.rb', line 532 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.
913 914 915 916 917 918 919 920 921 922 923 |
# File 'lib/rom/sql/relation/reading.rb', line 913 def lock(**, &) clause = lock_clause(**) if block_given? transaction do yield(dataset.lock_style(clause).to_a) end else new(dataset.lock_style(clause)) end end |
#map(key = nil) ⇒ Object
Map tuples from the relation
145 146 147 148 149 150 151 |
# File 'lib/rom/sql/relation/reading.rb', line 145 def map(key = nil, &) if key dataset.map(key, &) else dataset.map(&) end end |
#max(*args) ⇒ Object
Returns a result of SQL MAX clause.
318 319 320 |
# File 'lib/rom/sql/relation/reading.rb', line 318 def max(*args) dataset.__send__(__method__, *args) end |
#min(*args) ⇒ Object
Returns a result of SQL MIN clause.
304 305 306 |
# File 'lib/rom/sql/relation/reading.rb', line 304 def min(*args) dataset.__send__(__method__, *args) end |
#offset(num) ⇒ Relation
Set offset for the relation
546 547 548 |
# File 'lib/rom/sql/relation/reading.rb', line 546 def offset(num) new(dataset.__send__(__method__, num)) end |
#order(*columns) ⇒ Relation #order(*attributes) ⇒ Relation #order(&block) ⇒ Relation
Set order for the relation
478 479 480 481 482 483 484 |
# File 'lib/rom/sql/relation/reading.rb', line 478 def order(*args, &) if block_given? new(dataset.order(*args, *schema.canonical.order(&))) else new(dataset.__send__(__method__, *args, &)) end end |
#pluck(*names) ⇒ Array
Pluck values from a specific column
166 167 168 |
# File 'lib/rom/sql/relation/reading.rb', line 166 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
98 99 100 |
# File 'lib/rom/sql/relation/reading.rb', line 98 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
113 114 115 |
# File 'lib/rom/sql/relation/reading.rb', line 113 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
128 129 130 |
# File 'lib/rom/sql/relation/reading.rb', line 128 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.
1015 1016 1017 1018 1019 |
# File 'lib/rom/sql/relation/reading.rb', line 1015 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
888 889 890 |
# File 'lib/rom/sql/relation/reading.rb', line 888 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
183 184 185 |
# File 'lib/rom/sql/relation/reading.rb', line 183 def rename() schema.rename().(self) end |
#reverse ⇒ Relation
Reverse the order of the relation
506 507 508 |
# File 'lib/rom/sql/relation/reading.rb', line 506 def reverse(...) new(dataset.__send__(__method__, ...)) 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
694 695 696 |
# File 'lib/rom/sql/relation/reading.rb', line 694 def right_join(...) __join__(__method__, ...) end |
#select(*columns) ⇒ Relation #select(*attributes) ⇒ Relation #select(&block) ⇒ Relation #select(*columns, &block) ⇒ Relation Also known as: project
Select specific columns for select clause
240 241 242 |
# File 'lib/rom/sql/relation/reading.rb', line 240 def select(...) schema.project(...).(self) end |
#select_append ⇒ Relation
Append specific columns to select clause
252 253 254 |
# File 'lib/rom/sql/relation/reading.rb', line 252 def select_append(...) schema.merge(schema.canonical.project(...)).(self) end |
#select_group ⇒ Relation
Select and group by specific columns
804 805 806 807 |
# File 'lib/rom/sql/relation/reading.rb', line 804 def select_group(...) new_schema = schema.project(...) new_schema.(self).group(*new_schema) end |
#sum(*args) ⇒ Integer
Returns a result of SQL SUM clause.
290 291 292 |
# File 'lib/rom/sql/relation/reading.rb', line 290 def sum(*args) dataset.__send__(__method__, *args) end |
#unfiltered ⇒ SQL::Relation
Discard restrictions in ‘WHERE` and `HAVING` clauses
1029 1030 1031 |
# File 'lib/rom/sql/relation/reading.rb', line 1029 def unfiltered new(dataset.__send__(__method__)) end |
#union(relation, options = EMPTY_HASH) ⇒ Object
Adds a UNION clause for relation dataset using second relation dataset
@returRelation]
828 829 830 831 832 833 834 835 836 837 838 839 |
# File 'lib/rom/sql/relation/reading.rb', line 828 def union(relation, = EMPTY_HASH, &) # 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, &))) end |
#unique?(criteria) ⇒ TrueClass, FalseClass
Return if a restricted relation has 0 tuples
874 875 876 |
# File 'lib/rom/sql/relation/reading.rb', line 874 def unique?(criteria) !exist?(criteria) end |
#unordered ⇒ Relation
Removes ordering for the relation
494 495 496 |
# File 'lib/rom/sql/relation/reading.rb', line 494 def unordered new(dataset.unordered) end |
#where(conditions) ⇒ Relation #where(conditions, &block) ⇒ Relation #where(&block) ⇒ Relation
Restrict a relation to match criteria
364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/rom/sql/relation/reading.rb', line 364 def where(*args, &) if block_given? where(*args).where(schema.canonical.restriction(&)) 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
1043 1044 1045 1046 |
# File 'lib/rom/sql/relation/reading.rb', line 1043 def wrap(*names) others = names.map { |name| associations[name].wrapped } wrap_around(*others) end |