sunstone 6.0.0.4 → 6.1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  # end
21
21
  # end
22
22
  #
23
- def save!(*) #:nodoc:
23
+ def save!(**) #:nodoc:
24
24
  if instance_variable_defined?(:@no_save_transaction) && @no_save_transaction
25
25
  super
26
26
  else
@@ -35,29 +35,22 @@ module ActiveRecord
35
35
 
36
36
  def with_transaction_returning_status
37
37
  status = nil
38
+ connection = self.class.connection
38
39
 
39
- if self.class.connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && instance_variable_defined?(:@updating) && @updating
40
+ if connection.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter) && instance_variable_defined?(:@updating) && @updating
40
41
  status = yield
41
- status
42
42
  else
43
- self.class.transaction do
44
- if has_transactional_callbacks?
45
- add_to_transaction
46
- else
47
- sync_with_transaction_state if @transaction_state&.finalized?
48
- @transaction_state = self.class.connection.transaction_state
49
- end
43
+ ensure_finalize = !connection.transaction_open?
44
+ connection.transaction do
45
+ add_to_transaction(ensure_finalize || has_transactional_callbacks?)
50
46
  remember_transaction_record_state
51
47
 
52
48
  status = yield
53
49
  raise ActiveRecord::Rollback unless status
54
50
  end
55
- status
56
- end
57
- ensure
58
- if @transaction_state && @transaction_state.committed?
59
- clear_transaction_record_state
60
51
  end
52
+
53
+ status
61
54
  end
62
55
 
63
56
 
@@ -1,31 +1,31 @@
1
- module Arel
2
- module Attributes
3
- class EmptyRelation < Attribute
4
-
5
- attr_accessor :collection, :for_write
6
-
7
- def initialize(relation, name, collection = false, for_write=false)
8
- self[:relation] = relation
9
- self[:name] = name
10
- @collection = collection
11
- @for_write = for_write
12
- end
13
-
14
- def able_to_type_cast?
15
- false
16
- end
17
-
18
- def table_name
19
- nil
20
- end
21
-
22
- def eql? other
23
- self.class == other.class &&
24
- self.relation == other.relation &&
25
- self.name == other.name &&
26
- self.collection == other.collection
27
- end
28
-
29
- end
30
- end
31
- end
1
+ # module Arel
2
+ # module Attributes
3
+ # class EmptyRelation < Attribute
4
+ #
5
+ # attr_accessor :collection, :for_write
6
+ #
7
+ # def initialize(relation, name, collection = false, for_write=false)
8
+ # self[:relation] = relation
9
+ # self[:name] = name
10
+ # @collection = collection
11
+ # @for_write = for_write
12
+ # end
13
+ #
14
+ # def able_to_type_cast?
15
+ # false
16
+ # end
17
+ #
18
+ # def table_name
19
+ # nil
20
+ # end
21
+ #
22
+ # def eql? other
23
+ # self.class == other.class &&
24
+ # self.relation == other.relation &&
25
+ # self.name == other.name &&
26
+ # self.collection == other.collection
27
+ # end
28
+ #
29
+ # end
30
+ # end
31
+ # end
@@ -4,7 +4,7 @@ module Arel
4
4
 
5
5
  attr_accessor :eager_load
6
6
 
7
- def initialize cores = [SelectCore.new]
7
+ def initialize(cores = [SelectCore.new])
8
8
  super()
9
9
  @cores = cores
10
10
  @orders = []
@@ -2,8 +2,7 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  # Sunstone-specific extensions to column definitions in a table.
4
4
  class SunstoneColumn < Column #:nodoc:
5
- delegate :array, to: :sql_type_metadata
6
- alias :array? :array
5
+ attr_reader :array
7
6
 
8
7
  def initialize(name, sql_type_metadata, options={})
9
8
  @name = name.freeze
@@ -14,6 +13,7 @@ module ActiveRecord
14
13
  @collation = nil
15
14
  @table_name = nil
16
15
  @primary_key = (options['primary_key'] == true)
16
+ @array = options['array']
17
17
  end
18
18
 
19
19
  def primary_key?
@@ -47,15 +47,15 @@ module ActiveRecord
47
47
  # can be used to query the database repeatedly.
48
48
  def cacheable_query(klass, arel) # :nodoc:
49
49
  if prepared_statements
50
- sql, binds = visitor.accept(arel.ast, collector).value
50
+ sql, binds = visitor.compile(arel.ast, collector)
51
51
  query = klass.query(sql)
52
52
  elsif self.is_a?(ActiveRecord::ConnectionAdapters::SunstoneAPIAdapter)
53
53
  collector = SunstonePartialQueryCollector.new(self.collector)
54
- parts, binds = visitor.accept(arel.ast, collector).value
54
+ parts, binds = visitor.compile(arel.ast, collector)
55
55
  query = StatementCache::PartialQuery.new(parts, true)
56
56
  else
57
- collector = PartialQueryCollector.new
58
- parts, binds = visitor.accept(arel.ast, collector).value
57
+ collector = klass.partial_query_collector
58
+ parts, binds = visitor.compile(arel.ast, collector)
59
59
  query = klass.partial_query(parts)
60
60
  end
61
61
  [query, binds]
@@ -142,7 +142,7 @@ module ActiveRecord
142
142
 
143
143
  if sars[0].instance_variable_defined?(:@sunstone_calculation) && sars[0].instance_variable_get(:@sunstone_calculation)
144
144
  # this is a count, min, max.... yea i know..
145
- ActiveRecord::Result.new(['all'], [result], {:all => type_map.lookup('integer')})
145
+ ActiveRecord::Result.new(['all'], [result], {:all => type_map.lookup('integer', {})})
146
146
  elsif result.is_a?(Array)
147
147
  ActiveRecord::Result.new(result[0] ? result[0].keys : [], result.map{|r| r.values})
148
148
  else
@@ -31,7 +31,11 @@ module ActiveRecord
31
31
 
32
32
  version = Gem::Version.create(response['StandardAPI-Version'] || '5.0.0.4')
33
33
 
34
- @definitions[table_name] = if (version >= Gem::Version.create('5.0.0.5'))
34
+ @definitions[table_name] = if (version >= Gem::Version.create('6.0.0.29'))
35
+ schema = JSON.parse(response.body)
36
+ schema['columns'] = schema.delete('attributes')
37
+ schema
38
+ elsif (version >= Gem::Version.create('5.0.0.5'))
35
39
  JSON.parse(response.body)
36
40
  else
37
41
  { 'columns' => JSON.parse(response.body), 'limit' => nil }
@@ -46,7 +50,9 @@ module ActiveRecord
46
50
  # - format_type includes the column size constraint, e.g. varchar(50)
47
51
  # - ::regclass is a function that gives the id for a table name
48
52
  def column_definitions(table_name) # :nodoc:
49
- definition(table_name)['columns']
53
+ # First check for attributes and then for the deprecated columns field
54
+ # TODO: Remove after 0.3
55
+ definition(table_name)['attributes'] || definition(table_name)['columns']
50
56
  end
51
57
 
52
58
  # Returns the limit definition of the table (the maximum limit that can
@@ -58,28 +64,32 @@ module ActiveRecord
58
64
  def tables
59
65
  JSON.parse(@connection.get('/tables').body)
60
66
  end
61
-
67
+
62
68
  def views
63
69
  []
64
70
  end
65
-
71
+
66
72
  def new_column(name, options)
67
73
  sql_type_metadata = fetch_type_metadata(options)
68
74
  SunstoneColumn.new(name, sql_type_metadata, options)
69
75
  end
70
-
76
+
77
+ def lookup_cast_type(options)
78
+ type_map.lookup(options['type'], options.symbolize_keys)
79
+ end
80
+
71
81
  def fetch_type_metadata(options)
72
- cast_type = lookup_cast_type(options['type'])
82
+ cast_type = lookup_cast_type(options)
73
83
  simple_type = SqlTypeMetadata.new(
74
84
  sql_type: options['type'],
75
85
  type: cast_type.type,
76
86
  limit: cast_type.limit,
77
87
  precision: cast_type.precision,
78
- scale: cast_type.scale,
88
+ scale: cast_type.scale
79
89
  )
80
90
  SunstoneSQLTypeMetadata.new(simple_type, options)
81
91
  end
82
-
92
+
83
93
  def column_name_for_operation(operation, node) # :nodoc:
84
94
  visitor.accept(node, collector).first[operation.to_sym]
85
95
  end
@@ -0,0 +1,34 @@
1
+ require 'base64'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module Sunstone
6
+ module Type
7
+ class Binary < ActiveRecord::Type::Binary
8
+
9
+ # Converts a value from database input to the appropriate ruby type. The
10
+ # return value of this method will be returned from
11
+ # ActiveRecord::AttributeMethods::Read#read_attribute. The default
12
+ # implementation just calls Value#cast.
13
+ #
14
+ # +value+ The raw input, as provided from the database.
15
+ def deserialize(value)
16
+ value.nil? ? nil : Base64.strict_decode64(value)
17
+ end
18
+
19
+ # Casts a value from the ruby type to a type that the database knows how
20
+ # to understand. The returned value from this method should be a
21
+ # +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
22
+ # +nil+.
23
+ def serialize(value)
24
+ if limit && value.bytesize > limit
25
+ raise ActiveModel::RangeError, "value is out of range for #{self.class} with limit #{limit} bytes"
26
+ end
27
+ Base64.strict_encode64(value)
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,6 +1,7 @@
1
1
  require 'active_record/connection_adapters/abstract_adapter'
2
2
 
3
- #require 'active_record/connection_adapters/statement_pool'
3
+ require 'arel/nodes/relation'
4
+ require 'arel/visitors/to_sql_extensions'
4
5
 
5
6
  require 'active_record/connection_adapters/sunstone/database_statements'
6
7
  require 'active_record/connection_adapters/sunstone/schema_statements'
@@ -9,6 +10,7 @@ require 'active_record/connection_adapters/sunstone/column'
9
10
 
10
11
  require 'active_record/connection_adapters/sunstone/type/date_time'
11
12
  require 'active_record/connection_adapters/sunstone/type/array'
13
+ require 'active_record/connection_adapters/sunstone/type/binary'
12
14
  require 'active_record/connection_adapters/sunstone/type/uuid'
13
15
  require 'active_record/connection_adapters/sunstone/type/json'
14
16
 
@@ -30,7 +32,7 @@ module ActiveRecord
30
32
  conn_params[:port] ||= uri.port
31
33
  conn_params[:use_ssl] ||= (uri.scheme == 'https')
32
34
  end
33
-
35
+
34
36
  # Forward only valid config params to Sunstone::Connection
35
37
  conn_params.slice!(*VALID_SUNSTONE_CONN_PARAMS)
36
38
 
@@ -78,9 +80,9 @@ module ActiveRecord
78
80
 
79
81
  # Initializes and connects a SunstoneAPI adapter.
80
82
  def initialize(connection, logger, connection_parameters, config)
81
- super(connection, logger, config)
83
+ super(connection, logger, config.reverse_merge(prepared_statements: false))
82
84
 
83
- @prepared_statements = false
85
+ @prepared_statement_status = Concurrent::ThreadLocalVar.new(false)
84
86
  @connection_parameters = connection_parameters
85
87
 
86
88
  # @type_map = Type::HashLookupTypeMap.new
@@ -95,12 +97,12 @@ module ActiveRecord
95
97
  super
96
98
  @connection.reconnect!
97
99
  end
98
-
100
+
99
101
  def disconnect!
100
102
  super
101
103
  @connection.disconnect!
102
104
  end
103
-
105
+
104
106
  # Executes the delete statement and returns the number of rows affected.
105
107
  def delete(arel, name = nil, binds = [])
106
108
  r = exec_delete(arel, name, binds)
@@ -122,27 +124,28 @@ module ActiveRecord
122
124
  def update_table_definition(table_name, base) #:nodoc:
123
125
  SunstoneAPI::Table.new(table_name, base)
124
126
  end
125
-
127
+
126
128
  def arel_visitor
127
129
  Arel::Visitors::Sunstone.new
128
130
  end
129
-
131
+
130
132
  def collector
131
133
  Arel::Collectors::Sunstone.new
132
134
  end
133
-
135
+
134
136
  def server_config
135
137
  JSON.parse(@connection.get("/configuration").body)
136
138
  end
137
-
139
+
138
140
  def lookup_cast_type_from_column(column) # :nodoc:
139
- if column.array
140
- Sunstone::Type::Array.new(type_map.lookup(column.sql_type))
141
- else
142
- type_map.lookup(column.sql_type)
143
- end
141
+ cast_type = type_map.lookup(column.sql_type, {
142
+ limit: column.limit,
143
+ precision: column.precision,
144
+ scale: column.scale
145
+ })
146
+ column.array ? Sunstone::Type::Array.new(cast_type) : cast_type
144
147
  end
145
-
148
+
146
149
  def transaction(requires_new: nil, isolation: nil, joinable: true)
147
150
  Thread.current[:sunstone_transaction_count] ||= 0
148
151
  Thread.current[:sunstone_request_sent] = nil if Thread.current[:sunstone_transaction_count] == 0
@@ -159,7 +162,7 @@ module ActiveRecord
159
162
  rescue ActiveRecord::Rollback
160
163
  # rollbacks are silently swallowed
161
164
  end
162
-
165
+
163
166
  def supports_json?
164
167
  true
165
168
  end
@@ -176,33 +179,43 @@ module ActiveRecord
176
179
  exec_insert(arel, name, binds, pk, sequence_name)
177
180
  end
178
181
  alias create insert
179
-
182
+
180
183
  # Should be the defuat insert, but rails escapes if for SQL so we'll just
181
184
  # catch the string "DEFATUL VALUES" in the visitor
182
185
  # def empty_insert_statement_value
183
186
  # {}
184
187
  # end
185
-
188
+
186
189
  private
187
190
 
188
191
  def initialize_type_map(m) # :nodoc:
189
192
  m.register_type 'boolean', Type::Boolean.new
190
- m.register_type 'string', Type::String.new
191
- m.register_type 'integer', Type::Integer.new
192
- m.register_type 'decimal', Type::Decimal.new
193
+ m.register_type 'string' do |_, options|
194
+ Type::String.new(**options.slice(:limit))
195
+ end
196
+ m.register_type 'integer' do |_, options|
197
+ Type::Integer.new(**options.slice(:limit))
198
+ end
199
+ m.register_type 'decimal' do |_, options|
200
+ Type::Decimal.new(**options.slice(:precision, :scale))
201
+ end
202
+ m.register_type 'binary' do |_, options|
203
+ Sunstone::Type::Binary.new(**options.slice(:limit))
204
+ end
205
+
193
206
  m.register_type 'datetime', Sunstone::Type::DateTime.new
194
207
  m.register_type 'json', Sunstone::Type::Json.new
195
208
  m.register_type 'uuid', Sunstone::Type::Uuid.new
196
-
209
+
197
210
  if defined?(Sunstone::Type::EWKB)
198
211
  m.register_type 'ewkb', Sunstone::Type::EWKB.new
199
212
  end
200
213
  end
201
214
 
202
- def create_table_definition(name, temporary, options, as = nil) # :nodoc:
203
- SunstoneAPI::TableDefinition.new native_database_types, name, temporary, options, as
215
+ def create_table_definition(name, **options)
216
+ SunstoneAPI::TableDefinition.new(self, name, **options)
204
217
  end
205
-
218
+
206
219
  ActiveRecord::Type.add_modifier({ array: true }, Sunstone::Type::Array, adapter: :sunstone)
207
220
  # ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
208
221
  end
@@ -1,19 +1,13 @@
1
1
  require 'arel/visitors/visitor'
2
- class Arel::Visitors::Dot
3
- def visit_Arel_Nodes_Casted o
4
- # collector << quoted(o.val, o.attribute).to_s
5
- visit_String o.val
6
- end
7
- end
8
2
 
9
3
  module Arel
10
4
  module Visitors
11
5
  class Sunstone < Arel::Visitors::Visitor
12
6
 
13
- def compile node, &block
14
- accept(node, Arel::Collectors::SQLString.new, &block).value
7
+ def compile(node, collector = Arel::Collectors::Sunstone.new)
8
+ accept(node, collector).value
15
9
  end
16
-
10
+
17
11
  def preparable
18
12
  false
19
13
  end
@@ -67,28 +61,6 @@ module Arel
67
61
  collector
68
62
  end
69
63
 
70
- def visit_Arel_Nodes_Overlaps o, collector
71
- key = visit(o.left, collector)
72
- value = { overlaps: visit(o.right, collector) }
73
- if key.is_a?(Hash)
74
- add_to_bottom_of_hash_or_array(key, value)
75
- key
76
- else
77
- {key => value}
78
- end
79
- end
80
-
81
- def visit_Arel_Nodes_NotOverlaps o, collector
82
- key = visit(o.left, collector)
83
- value = { not_overlaps: visit(o.right, collector) }
84
- if key.is_a?(Hash)
85
- add_to_bottom_of_hash_or_array(key, value)
86
- key
87
- else
88
- {key => value}
89
- end
90
- end
91
-
92
64
  def visit_Arel_Nodes_InsertStatement o, collector
93
65
  collector.request_type = Net::HTTP::Post
94
66
  collector.table = o.relation.name
@@ -255,7 +227,7 @@ module Arel
255
227
  #
256
228
  def visit_Arel_Nodes_Casted o, collector
257
229
  # collector << quoted(o.val, o.attribute).to_s
258
- o.val
230
+ o.value
259
231
  end
260
232
 
261
233
  def visit_Arel_Nodes_Quoted o, collector
@@ -731,6 +703,7 @@ module Arel
731
703
  {key => value}
732
704
  end
733
705
  end
706
+ alias_method :visit_Arel_Nodes_HomogeneousIn, :visit_Arel_Nodes_In
734
707
 
735
708
  def visit_Arel_Nodes_NotIn o, collector
736
709
  key = visit(o.left, collector)
@@ -947,9 +920,12 @@ module Arel
947
920
  value = if o.relation.is_a?(Arel::Attributes::Relation)
948
921
  { o.name => visit_Arel_Attributes_Relation(o.relation, collector, false) }
949
922
  else
950
- visit(o.relation, collector)
923
+ if o.relation.is_a?(Arel::Attributes::Attribute)
924
+ { o.name => o.relation.name }
925
+ else
926
+ visit(o.relation, collector)
927
+ end
951
928
  end
952
- # value = value.to_s.split('.').last if !value.is_a?(Hash)
953
929
 
954
930
  if o.collection
955
931
  ary = []
@@ -972,9 +948,9 @@ module Arel
972
948
  end
973
949
  end
974
950
 
975
- def visit_Arel_Attributes_EmptyRelation o, collector, top=true
976
- o.for_write ? "#{o.name}_attributes" : o.name
977
- end
951
+ # def visit_Arel_Attributes_EmptyRelation o, collector, top=true
952
+ # o.for_write ? "#{o.name}_attributes" : o.name
953
+ # end
978
954
 
979
955
  def visit_Arel_Attributes_Attribute o, collector
980
956
  join_name = o.relation.table_alias || o.relation.name