sunstone 6.0.0.4 → 6.1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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