Class: CodeToQuery::Query
- Inherits:
-
Object
- Object
- CodeToQuery::Query
- Defined in:
- lib/code_to_query/query.rb
Instance Attribute Summary collapse
-
#intent ⇒ Object
readonly
Returns the value of attribute intent.
-
#metrics ⇒ Object
readonly
Returns the value of attribute metrics.
-
#params ⇒ Object
readonly
Returns the value of attribute params.
-
#sql ⇒ Object
readonly
Returns the value of attribute sql.
Instance Method Summary collapse
- #binds ⇒ Object
- #explain ⇒ Object
-
#initialize(sql:, params:, bind_spec:, intent:, allow_tables:, config:) ⇒ Query
constructor
A new instance of Query.
- #relationable? ⇒ Boolean
- #run ⇒ Object
- #safe? ⇒ Boolean
- #to_active_record ⇒ Object
- #to_relation ⇒ Object
- #to_relation! ⇒ Object
Constructor Details
#initialize(sql:, params:, bind_spec:, intent:, allow_tables:, config:) ⇒ Query
Returns a new instance of Query.
12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/code_to_query/query.rb', line 12 def initialize(sql:, params:, bind_spec:, intent:, allow_tables:, config:) @sql = sql @params = params || {} @bind_spec = bind_spec || [] @intent = intent || {} @allow_tables = allow_tables @config = config @safety_checked = false @safety_result = nil @metrics = extract_metrics_from_intent(@intent) end |
Instance Attribute Details
#intent ⇒ Object (readonly)
Returns the value of attribute intent.
10 11 12 |
# File 'lib/code_to_query/query.rb', line 10 def intent @intent end |
#metrics ⇒ Object (readonly)
Returns the value of attribute metrics.
10 11 12 |
# File 'lib/code_to_query/query.rb', line 10 def metrics @metrics end |
#params ⇒ Object (readonly)
Returns the value of attribute params.
10 11 12 |
# File 'lib/code_to_query/query.rb', line 10 def params @params end |
#sql ⇒ Object (readonly)
Returns the value of attribute sql.
10 11 12 |
# File 'lib/code_to_query/query.rb', line 10 def sql @sql end |
Instance Method Details
#binds ⇒ Object
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 |
# File 'lib/code_to_query/query.rb', line 24 def binds return [] unless defined?(ActiveRecord::Base) connection = if @config.readonly_role && ActiveRecord.respond_to?(:connected_to) ActiveRecord::Base.connected_to(role: @config.readonly_role) do ActiveRecord::Base.connection end else ActiveRecord::Base.connection end @bind_spec.map do |bind_info| key = bind_info[:key] column_name = bind_info[:column] # Get parameter value (check both string and symbol keys) value = @params[key.to_s] || @params[key.to_sym] # Determine the correct ActiveRecord type type = infer_column_type(connection, @intent['table'], column_name, bind_info[:cast]) ActiveRecord::Relation::QueryAttribute.new(column_name.to_s, value, type) end rescue StandardError => e @config.logger.warn("[code_to_query] Failed to build binds: #{e.message}") [] end |
#explain ⇒ Object
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 |
# File 'lib/code_to_query/query.rb', line 59 def explain return 'EXPLAIN unavailable (ActiveRecord not loaded)' unless defined?(ActiveRecord::Base) explain_sql = case @config.adapter when :postgres, :postgresql "EXPLAIN (ANALYZE false, VERBOSE false, BUFFERS false) #{@sql}" when :mysql "EXPLAIN #{@sql}" when :sqlite "EXPLAIN QUERY PLAN #{@sql}" else "EXPLAIN #{@sql}" end result = if @config.readonly_role && ActiveRecord.respond_to?(:connected_to) ActiveRecord::Base.connected_to(role: @config.readonly_role) do ActiveRecord::Base.connection.execute(explain_sql) end else ActiveRecord::Base.connection.execute(explain_sql) end format_explain_result(result) rescue StandardError => e "EXPLAIN failed: #{e.message}" end |
#relationable? ⇒ Boolean
120 121 122 123 124 125 |
# File 'lib/code_to_query/query.rb', line 120 def relationable? return false unless defined?(ActiveRecord::Base) return false unless @intent['type'] == 'select' !!infer_model_for_table(@intent['table']) end |
#run ⇒ Object
134 135 136 |
# File 'lib/code_to_query/query.rb', line 134 def run Runner.new(@config).run(sql: @sql, binds: binds) end |
#safe? ⇒ Boolean
52 53 54 55 56 57 |
# File 'lib/code_to_query/query.rb', line 52 def safe? return @safety_result if @safety_checked @safety_checked = true @safety_result = perform_safety_checks end |
#to_active_record ⇒ Object
116 117 118 |
# File 'lib/code_to_query/query.rb', line 116 def to_active_record to_relation end |
#to_relation ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/code_to_query/query.rb', line 86 def to_relation return nil unless defined?(ActiveRecord::Base) return nil unless @intent['type'] == 'select' table_name = @intent['table'] model = infer_model_for_table(table_name) return nil unless model scope = model.all # Apply WHERE conditions Array(@intent['filters']).each do |filter| scope = apply_filter_to_scope(scope, filter) end # Apply ORDER BY Array(@intent['order']).each do |order_spec| column = order_spec['column'] direction = order_spec['dir']&.downcase == 'asc' ? :asc : :desc scope = scope.order(column => direction) end # Apply LIMIT (intelligent based on query type) limit = determine_appropriate_limit scope.limit(limit) if limit rescue StandardError => e @config.logger.warn("[code_to_query] Failed to build relation: #{e.message}") nil end |
#to_relation! ⇒ Object
127 128 129 130 131 132 |
# File 'lib/code_to_query/query.rb', line 127 def to_relation! rel = to_relation return rel if rel raise CodeToQuery::NotRelationConvertibleError, 'Query cannot be expressed as ActiveRecord::Relation' end |