Method: PgQuery::ParserResult#filter_columns
- Defined in:
- lib/pg_query/filter_columns.rb
#filter_columns ⇒ Object
Returns a list of columns that the query filters by - this excludes the target list, but includes things like JOIN condition and WHERE clause.
Note: This also traverses into sub-selects.
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 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 91 |
# File 'lib/pg_query/filter_columns.rb', line 7 def filter_columns # rubocop:disable Metrics/CyclomaticComplexity load_objects! if @aliases.nil? # Get condition items from the parsetree statements = @tree.stmts.dup.to_a.map(&:stmt) condition_items = [] filter_columns = [] loop do statement = statements.shift if statement case statement.node when :list statements += statement.list.items when :raw_stmt statements << statement.raw_stmt.stmt when :select_stmt case statement.select_stmt.op when :SETOP_NONE if statement.select_stmt.from_clause # FROM subselects statement.select_stmt.from_clause.each do |item| next unless item['RangeSubselect'] statements << item['RangeSubselect']['subquery'] end # JOIN ON conditions condition_items += conditions_from_join_clauses(statement.select_stmt.from_clause) end # WHERE clause condition_items << statement.select_stmt.where_clause if statement.select_stmt.where_clause # CTEs if statement.select_stmt.with_clause statement.select_stmt.with_clause.ctes.each do |item| statements << item.common_table_expr.ctequery if item.node == :common_table_expr end end when :SETOP_UNION, :SETOP_EXCEPT, :SETOP_INTERSECT statements << PgQuery::Node.new(select_stmt: statement.select_stmt.larg) if statement.select_stmt.larg statements << PgQuery::Node.new(select_stmt: statement.select_stmt.rarg) if statement.select_stmt.rarg end when :update_stmt condition_items << statement.update_stmt.where_clause if statement.update_stmt.where_clause when :delete_stmt condition_items << statement.delete_stmt.where_clause if statement.delete_stmt.where_clause when :index_stmt condition_items << statement.index_stmt.where_clause if statement.index_stmt.where_clause end end # Process both JOIN and WHERE conditions here next_item = condition_items.shift if next_item case next_item.node when :a_expr condition_items << next_item.a_expr.lexpr if next_item.a_expr.lexpr condition_items << next_item.a_expr.rexpr if next_item.a_expr.rexpr when :bool_expr condition_items += next_item.bool_expr.args when :coalesce_expr condition_items += next_item.coalesce_expr.args when :row_expr condition_items += next_item.row_expr.args when :column_ref column, table = next_item.column_ref.fields.map { |f| f.string.sval }.reverse filter_columns << [@aliases[table] || table, column] when :null_test condition_items << next_item.null_test.arg when :boolean_test condition_items << next_item.boolean_test.arg when :func_call # FIXME: This should actually be extracted as a funccall and be compared with those indices condition_items += next_item.func_call.args if next_item.func_call.args when :sub_link condition_items << next_item.sub_link.testexpr statements << next_item.sub_link.subselect end end break if statements.empty? && condition_items.empty? end filter_columns.uniq end |