Module: Unreliable::BuildOrder
- Defined in:
- lib/unreliable/build_order.rb
Instance Method Summary collapse
- #build_order(arel) ⇒ Object
- #distinct_on_postgres?(adapter_name) ⇒ Boolean
- #from_one_table_with_ordered_pk?(arel) ⇒ Boolean
- #from_only_internal_metadata?(arel) ⇒ Boolean
- #order_columns(arel) ⇒ Object
- #primary_key_columns(arel) ⇒ Object
Instance Method Details
#build_order(arel) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/unreliable/build_order.rb', line 9 def build_order(arel) super(arel) adapter_name = Arel::Table.engine.connection.adapter_name return unless Unreliable::Config.enabled? return if distinct_on_postgres?(adapter_name) return if (arel) return if from_one_table_with_ordered_pk?(arel) case adapter_name when "Mysql2" # https://dev.mysql.com/doc/refman/8.0/en/mathematical-functions.html#function_rand arel.order("RAND()") when "PostgreSQL", "SQLite" # https://www.postgresql.org/docs/16/functions-math.html#FUNCTIONS-MATH-RANDOM-TABLE # https://www.sqlite.org/lang_corefunc.html#random arel.order("RANDOM()") else raise ArgumentError, "unknown Arel::Table.engine" end end |
#distinct_on_postgres?(adapter_name) ⇒ Boolean
34 35 36 |
# File 'lib/unreliable/build_order.rb', line 34 def distinct_on_postgres?(adapter_name) distinct_value && adapter_name == "PostgreSQL" end |
#from_one_table_with_ordered_pk?(arel) ⇒ Boolean
43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/unreliable/build_order.rb', line 43 def from_one_table_with_ordered_pk?(arel) # This gem isn't (yet) capable of determining if ordering is reliable when two or # more tables are being joined. return false if arel.ast.cores.first.source.is_a?(Arel::Nodes::JoinSource) && arel.ast.cores.first.source.right.present? return false if arel.froms.count > 1 # If the single table's primary key's column(s) are covered by the order columns, # return true and don't randomize the order. (primary_key_columns(arel) - order_columns(arel)).empty? end |
#from_only_internal_metadata?(arel) ⇒ Boolean
38 39 40 41 |
# File 'lib/unreliable/build_order.rb', line 38 def (arel) # No need to randomize queries on ar_internal_metadata arel.froms.map(&:name) == [ActiveRecord::Base.] end |
#order_columns(arel) ⇒ Object
63 64 65 66 67 68 69 70 71 |
# File 'lib/unreliable/build_order.rb', line 63 def order_columns(arel) from_table_name = arel.froms.first.name arel.orders .select { |order| order.is_a? Arel::Nodes::Ordering } # Don't try to parse textual orders .map(&:expr) .select { |expr| expr.relation.name == from_table_name } .map(&:name) .map(&:to_s) # In Rails < 5.2, the order column names are symbols; >= 5.2, strings end |
#primary_key_columns(arel) ⇒ Object
55 56 57 58 59 60 61 |
# File 'lib/unreliable/build_order.rb', line 55 def primary_key_columns(arel) # primary_keys returns a String if it's one column, an Array if two or more. # Using the SchemaCache minimizes the number of times we have to, e.g. in MySQL, # SELECT column_name FROM information_schema.statistics # (or in Rails < 6, SELECT column_name FROM information_schema.key_column_usage) [ActiveRecord::Base.connection.schema_cache.primary_keys(arel.froms.first.name)].flatten end |