Module: ActiveRecord::ConnectionAdapters::Sunstone::DatabaseStatements

Defined in:
lib/active_record/connection_adapters/sunstone/database_statements.rb

Defined Under Namespace

Classes: SunstonePartialQueryCollector

Instance Method Summary collapse

Instance Method Details

#cacheable_query(klass, arel) ⇒ Object

This is used in the StatementCache object. It returns an object that can be used to query the database repeatedly.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 48

def cacheable_query(klass, arel) # :nodoc:
  if prepared_statements
    sql, binds = visitor.compile(arel.ast, collector)
    query = klass.query(sql)
  elsif self.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
    collector = SunstonePartialQueryCollector.new(self.collector)
    parts, binds = visitor.compile(arel.ast, collector)
    query = StatementCache::PartialQuery.new(parts, true)
  else
    collector = klass.partial_query_collector
    parts, binds = visitor.compile(arel.ast, collector)
    query = klass.partial_query(parts)
  end
  [query, binds]
end

#delete(arel, name = nil, binds = []) ⇒ Object



166
167
168
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 166

def delete(arel, name = nil, binds = [])
  exec_delete(arel, name, binds)
end

#exec_query(arel, name = 'SAR', binds = [], prepare: false) ⇒ Object



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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 88

def exec_query(arel, name = 'SAR', binds = [], prepare: false)
  sars = []
  multiple_requests = arel.is_a?(Arel::Collectors::Sunstone)
  type_casted_binds = binds#type_casted_binds(binds)
  
  if multiple_requests
    allowed_limit = limit_definition(arel.table)
    limit_bind_index = nil#binds.find_index { |x| x.name == 'LIMIT' }
    requested_limit = if limit_bind_index
      type_casted_binds[limit_bind_index]
    else
      arel.limit&.value&.value_for_database
    end

    if allowed_limit.nil?
      multiple_requests = false
    elsif requested_limit && requested_limit <= allowed_limit
      multiple_requests = false
    else
      multiple_requests = true
    end
  end

  send_request = lambda { |req_arel|
    sar = to_sar(req_arel, type_casted_binds)
    sars.push(sar)
    log_mess = sar.path.split('?', 2)
    log("#{sar.method} #{log_mess[0]} #{(log_mess[1] && !log_mess[1].empty?) ? MessagePack.unpack(CGI.unescape(log_mess[1])) : '' }", name) do
      response = @connection.send_request(sar)
      if response.is_a?(Net::HTTPNoContent)
        nil
      else
        JSON.parse(response.body)
      end
    end
  }

  result = if multiple_requests
    binds.delete_at(limit_bind_index) if limit_bind_index

    limit, offset, results = allowed_limit, 0, []
    while requested_limit ? offset < requested_limit : true
      split_arel = arel.dup
      split_arel.limit = limit
      split_arel.offset = offset
      request_results = send_request.call(split_arel)
      results = results + request_results
      break if request_results.size < limit
      offset = offset + limit
    end
    results
  else
    send_request.call(arel)
  end
  
  if sars[0].instance_variable_defined?(:@sunstone_calculation) && sars[0].instance_variable_get(:@sunstone_calculation)
    # this is a count, min, max.... yea i know..
    ActiveRecord::Result.new(['all'], [result], {:all => type_map.lookup('integer', {})})
  elsif result.is_a?(Array)
    ActiveRecord::Result.new(result[0] ? result[0].keys : [], result.map{|r| r.values})
  else
    ActiveRecord::Result.new(result.keys, [result])
  end
end

#insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) ⇒ Object



153
154
155
156
157
158
159
160
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 153

def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
  sar, binds = to_sar_and_binds(arel, binds)
  value = exec_insert(sar, name, binds, pk, sequence_name)
  id_value || last_inserted_id(value)
  
  # value = exec_insert(arel, name, binds, pk, sequence_name)
  # id_value || last_inserted_id(value)
end

#last_inserted_id(result) ⇒ Object



170
171
172
173
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 170

def last_inserted_id(result)
  row = result.rows.first
  row && row['id']
end

#select_all(arel, name = nil, binds = [], preparable: nil) ⇒ Object

Returns an ActiveRecord::Result instance.



82
83
84
85
86
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 82

def select_all(arel, name = nil, binds = [], preparable: nil)
  arel = arel_from_relation(arel)
  sar, binds = to_sar_and_binds(arel, binds)
  select(sar, name, binds)
end

#to_sar(arel_or_sar_string, binds = nil) ⇒ Object

Converts an arel AST to a Sunstone API Request



21
22
23
24
25
26
27
28
29
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 21

def to_sar(arel_or_sar_string, binds = nil)
  if arel_or_sar_string.respond_to?(:ast)
    sar = visitor.accept(arel_or_sar_string.ast, collector)
    binds = sar.binds if binds.nil?
  else
    sar = arel_or_sar_string
  end
  sar.compile(binds)
end

#to_sar_and_binds(arel_or_sar_string, binds = []) ⇒ Object

:nodoc:



31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 31

def to_sar_and_binds(arel_or_sar_string, binds = []) # :nodoc:
  if arel_or_sar_string.respond_to?(:ast)
    unless binds.empty?
      raise "Passing bind parameters with an arel AST is forbidden. " \
        "The values must be stored on the AST directly"
    end
    sar = visitor.accept(arel_or_sar_string.ast, collector)
    # puts ['a', sar.freeze, sar.binds].map(&:inspect)
    [sar.freeze, sar.binds]
  else
    # puts ['b',arel_or_sar_string.dup.freeze, binds].map(&:inspect)
    [arel_or_sar_string.dup.freeze, binds]
  end
end

#to_sql(arel, binds = []) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 8

def to_sql(arel, binds = [])
  if arel.respond_to?(:ast)
    unless binds.empty?
      raise "Passing bind parameters with an arel AST is forbidden. " \
        "The values must be stored on the AST directly"
    end
    Arel::Visitors::ToSql.new(self).accept(arel.ast, Arel::Collectors::SubstituteBinds.new(self, Arel::Collectors::SQLString.new)).value
  else
    arel.dup.freeze
  end
end

#update(arel, name = nil, binds = []) ⇒ Object



162
163
164
# File 'lib/active_record/connection_adapters/sunstone/database_statements.rb', line 162

def update(arel, name = nil, binds = [])
  exec_update(arel, name, binds)
end