torque-postgresql 2.0.3 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/torque/postgresql.rb +1 -0
- data/lib/torque/postgresql/adapter.rb +23 -0
- data/lib/torque/postgresql/adapter/database_statements.rb +2 -0
- data/lib/torque/postgresql/adapter/oid.rb +3 -1
- data/lib/torque/postgresql/adapter/oid/box.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/circle.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/enum.rb +5 -0
- data/lib/torque/postgresql/adapter/oid/enum_set.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/interval.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/line.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/range.rb +2 -0
- data/lib/torque/postgresql/adapter/oid/segment.rb +2 -0
- data/lib/torque/postgresql/adapter/quoting.rb +2 -0
- data/lib/torque/postgresql/adapter/schema_creation.rb +8 -1
- data/lib/torque/postgresql/adapter/schema_definitions.rb +2 -0
- data/lib/torque/postgresql/adapter/schema_dumper.rb +9 -3
- data/lib/torque/postgresql/adapter/schema_statements.rb +2 -0
- data/lib/torque/postgresql/arel/infix_operation.rb +5 -1
- data/lib/torque/postgresql/arel/join_source.rb +2 -0
- data/lib/torque/postgresql/arel/nodes.rb +2 -0
- data/lib/torque/postgresql/arel/operations.rb +2 -0
- data/lib/torque/postgresql/arel/select_manager.rb +2 -0
- data/lib/torque/postgresql/arel/visitors.rb +6 -3
- data/lib/torque/postgresql/associations/association.rb +14 -3
- data/lib/torque/postgresql/associations/association_scope.rb +2 -0
- data/lib/torque/postgresql/associations/belongs_to_many_association.rb +168 -48
- data/lib/torque/postgresql/associations/builder/belongs_to_many.rb +8 -5
- data/lib/torque/postgresql/associations/builder/has_many.rb +2 -0
- data/lib/torque/postgresql/associations/preloader/association.rb +30 -1
- data/lib/torque/postgresql/attributes/builder.rb +3 -1
- data/lib/torque/postgresql/attributes/builder/enum.rb +10 -8
- data/lib/torque/postgresql/attributes/builder/period.rb +6 -4
- data/lib/torque/postgresql/attributes/enum.rb +6 -11
- data/lib/torque/postgresql/attributes/enum_set.rb +3 -1
- data/lib/torque/postgresql/attributes/lazy.rb +3 -1
- data/lib/torque/postgresql/attributes/period.rb +2 -0
- data/lib/torque/postgresql/autosave_association.rb +19 -16
- data/lib/torque/postgresql/auxiliary_statement.rb +2 -0
- data/lib/torque/postgresql/auxiliary_statement/settings.rb +2 -0
- data/lib/torque/postgresql/base.rb +11 -2
- data/lib/torque/postgresql/coder.rb +5 -3
- data/lib/torque/postgresql/collector.rb +2 -0
- data/lib/torque/postgresql/config.rb +5 -0
- data/lib/torque/postgresql/geometry_builder.rb +2 -0
- data/lib/torque/postgresql/i18n.rb +2 -0
- data/lib/torque/postgresql/inheritance.rb +2 -0
- data/lib/torque/postgresql/insert_all.rb +26 -0
- data/lib/torque/postgresql/migration/command_recorder.rb +2 -0
- data/lib/torque/postgresql/railtie.rb +2 -0
- data/lib/torque/postgresql/reflection.rb +2 -0
- data/lib/torque/postgresql/reflection/abstract_reflection.rb +13 -28
- data/lib/torque/postgresql/reflection/association_reflection.rb +24 -0
- data/lib/torque/postgresql/reflection/belongs_to_many_reflection.rb +2 -0
- data/lib/torque/postgresql/reflection/has_many_reflection.rb +2 -0
- data/lib/torque/postgresql/reflection/runtime_reflection.rb +2 -0
- data/lib/torque/postgresql/reflection/through_reflection.rb +2 -0
- data/lib/torque/postgresql/relation.rb +15 -11
- data/lib/torque/postgresql/relation/auxiliary_statement.rb +6 -1
- data/lib/torque/postgresql/relation/distinct_on.rb +2 -0
- data/lib/torque/postgresql/relation/inheritance.rb +2 -0
- data/lib/torque/postgresql/relation/merger.rb +2 -0
- data/lib/torque/postgresql/schema_cache.rb +2 -0
- data/lib/torque/postgresql/version.rb +3 -1
- data/spec/schema.rb +3 -2
- data/spec/tests/arel_spec.rb +3 -1
- data/spec/tests/belongs_to_many_spec.rb +139 -13
- data/spec/tests/enum_set_spec.rb +1 -1
- data/spec/tests/has_many_spec.rb +15 -1
- data/spec/tests/insert_all_spec.rb +89 -0
- data/spec/tests/table_inheritance_spec.rb +1 -1
- metadata +9 -6
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Associations
|
@@ -55,12 +57,9 @@ module Torque
|
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
58
|
-
|
59
|
-
model.after_create callback.call(:saved_changes), if: :saved_changes?
|
60
|
-
model.after_destroy callback.call(:changes_to_save)
|
61
|
-
end
|
62
|
-
|
60
|
+
model.after_create callback.call(:saved_changes), if: :saved_changes?
|
63
61
|
model.after_update callback.call(:saved_changes), if: :saved_changes?
|
62
|
+
model.after_destroy callback.call(:changes_to_save)
|
64
63
|
model.after_touch callback.call(:changes_to_save)
|
65
64
|
end
|
66
65
|
|
@@ -95,6 +94,10 @@ module Torque
|
|
95
94
|
end
|
96
95
|
end
|
97
96
|
|
97
|
+
def self.add_destroy_callbacks(model, reflection)
|
98
|
+
model.after_destroy lambda { |o| o.association(reflection.name).handle_dependency }
|
99
|
+
end
|
100
|
+
|
98
101
|
def self.define_validations(model, reflection)
|
99
102
|
if reflection.options.key?(:required)
|
100
103
|
reflection.options[:optional] = !reflection.options.delete(:required)
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Associations
|
@@ -33,16 +35,43 @@ module Torque
|
|
33
35
|
ids.each { |id| records[id].concat(Array.wrap(record)) }
|
34
36
|
end
|
35
37
|
|
38
|
+
records.default_proc = nil
|
36
39
|
owners.each do |owner|
|
37
40
|
associate_records_to_owner(owner, records[owner[owner_key_name]] || [])
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
44
|
+
if PostgreSQL::AR610
|
45
|
+
# This is how Rails 6.1 now load the records
|
46
|
+
def load_records
|
47
|
+
return super unless connected_through_array?
|
48
|
+
|
49
|
+
@records_by_owner = {}.compare_by_identity
|
50
|
+
raw_records = owner_keys.empty? ? [] : records_for(owner_keys)
|
51
|
+
|
52
|
+
@preloaded_records = raw_records.select do |record|
|
53
|
+
assignments = false
|
54
|
+
|
55
|
+
ids = convert_key(record[association_key_name])
|
56
|
+
owners_by_key.values_at(*ids).flat_map do |owner|
|
57
|
+
entries = (@records_by_owner[owner] ||= [])
|
58
|
+
|
59
|
+
if reflection.collection? || entries.empty?
|
60
|
+
entries << record
|
61
|
+
assignments = true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
assignments
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
41
70
|
# Build correctly the constraint condition in order to get the
|
42
71
|
# associated ids
|
43
72
|
def records_for(ids, &block)
|
44
73
|
return super unless connected_through_array?
|
45
|
-
condition = scope.
|
74
|
+
condition = scope.arel_table[association_key_name]
|
46
75
|
condition = reflection.build_id_constraint(condition, ids.flatten.uniq)
|
47
76
|
scope.where(condition).load(&block)
|
48
77
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'builder/enum'
|
2
4
|
require_relative 'builder/period'
|
3
5
|
|
@@ -7,7 +9,7 @@ module Torque
|
|
7
9
|
module Builder
|
8
10
|
def self.include_on(klass, method_name, builder_klass, **extra, &block)
|
9
11
|
klass.define_singleton_method(method_name) do |*args, **options|
|
10
|
-
return unless
|
12
|
+
return unless table_exists?
|
11
13
|
|
12
14
|
args.each do |attribute|
|
13
15
|
begin
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Attributes
|
@@ -31,13 +33,13 @@ module Torque
|
|
31
33
|
def values_methods
|
32
34
|
return @values_methods if defined?(@values_methods)
|
33
35
|
|
34
|
-
prefix = options.fetch(:prefix, nil)
|
35
|
-
suffix = options.fetch(:suffix, nil)
|
36
|
+
prefix = options.fetch(:prefix, nil)
|
37
|
+
suffix = options.fetch(:suffix, nil)
|
36
38
|
|
37
|
-
prefix = attribute
|
38
|
-
suffix =
|
39
|
+
prefix = attribute if prefix == true
|
40
|
+
suffix = attribute if suffix == true
|
39
41
|
|
40
|
-
base =
|
42
|
+
base = [prefix, '%s', suffix].compact.join('_')
|
41
43
|
|
42
44
|
@values_methods = begin
|
43
45
|
values.map do |val|
|
@@ -153,12 +155,12 @@ module Torque
|
|
153
155
|
cast_type = subtype.name.chomp('[]')
|
154
156
|
klass_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
155
157
|
def has_#{attribute.pluralize}(*values) # def has_roles(*values)
|
156
|
-
attr =
|
158
|
+
attr = arel_table['#{attribute}'] # attr = arel_table['role']
|
157
159
|
where(attr.contains(::Arel.array(values, cast: '#{cast_type}'))) # where(attr.contains(::Arel.array(values, cast: 'roles')))
|
158
160
|
end # end
|
159
161
|
|
160
162
|
def has_any_#{attribute.pluralize}(*values) # def has_roles(*values)
|
161
|
-
attr =
|
163
|
+
attr = arel_table['#{attribute}'] # attr = arel_table['role']
|
162
164
|
where(attr.overlaps(::Arel.array(values, cast: '#{cast_type}'))) # where(attr.overlaps(::Arel.array(values, cast: 'roles')))
|
163
165
|
end # end
|
164
166
|
RUBY
|
@@ -184,7 +186,7 @@ module Torque
|
|
184
186
|
values_methods.each do |key, (scope, ask, bang, val)|
|
185
187
|
klass_content += <<-RUBY
|
186
188
|
def #{scope} # def admin
|
187
|
-
attr =
|
189
|
+
attr = arel_table['#{attribute}'] # attr = arel_table['role']
|
188
190
|
where(::#{enum_klass}.scope(attr, '#{val}')) # where(Enum::Roles.scope(attr, 'admin'))
|
189
191
|
end # end
|
190
192
|
RUBY
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Attributes
|
@@ -202,7 +204,7 @@ module Torque
|
|
202
204
|
end
|
203
205
|
|
204
206
|
def arel_attribute
|
205
|
-
@arel_attribute ||= "
|
207
|
+
@arel_attribute ||= "arel_table[#{attribute.inspect}]"
|
206
208
|
end
|
207
209
|
|
208
210
|
def arel_default_sql
|
@@ -245,7 +247,7 @@ module Torque
|
|
245
247
|
def arel_real_start_at
|
246
248
|
return arel_start_at unless threshold.present?
|
247
249
|
@arel_real_start_at ||= begin
|
248
|
-
result = "(#{arel_start_at} - #{arel_threshold_value})"
|
250
|
+
result = +"(#{arel_start_at} - #{arel_threshold_value})"
|
249
251
|
result << '.cast(:date)' if type.eql?(:daterange)
|
250
252
|
result
|
251
253
|
end
|
@@ -255,7 +257,7 @@ module Torque
|
|
255
257
|
def arel_real_finish_at
|
256
258
|
return arel_finish_at unless threshold.present?
|
257
259
|
@arel_real_finish_at ||= begin
|
258
|
-
result = "(#{arel_finish_at} + #{arel_threshold_value})"
|
260
|
+
result = +"(#{arel_finish_at} + #{arel_threshold_value})"
|
259
261
|
result << '.cast(:date)' if type.eql?(:daterange)
|
260
262
|
result
|
261
263
|
end
|
@@ -276,7 +278,7 @@ module Torque
|
|
276
278
|
|
277
279
|
# Create an arel named function
|
278
280
|
def arel_named_function(name, *args)
|
279
|
-
result = "::Arel::Nodes::NamedFunction.new(#{name.to_s.inspect}"
|
281
|
+
result = +"::Arel::Nodes::NamedFunction.new(#{name.to_s.inspect}"
|
280
282
|
result << ', [' << args.join(', ') << ']' if args.present?
|
281
283
|
result << ')'
|
282
284
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Attributes
|
@@ -27,15 +29,10 @@ module Torque
|
|
27
29
|
def include_on(klass, method_name = nil)
|
28
30
|
method_name ||= Torque::PostgreSQL.config.enum.base_method
|
29
31
|
Builder.include_on(klass, method_name, Builder::Enum) do |builder|
|
30
|
-
defined_enums[builder.attribute.
|
32
|
+
defined_enums[builder.attribute.to_s] = builder.subtype
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
34
|
-
# You can specify the connection name for each enum
|
35
|
-
def connection_specification_name
|
36
|
-
return self == Enum ? 'primary' : superclass.connection_specification_name
|
37
|
-
end
|
38
|
-
|
39
36
|
# Overpass new so blank values return only nil
|
40
37
|
def new(value)
|
41
38
|
return Lazy.new(self, LAZY_VALUE) if value.blank?
|
@@ -45,9 +42,7 @@ module Torque
|
|
45
42
|
# Load the list of values in a lazy way
|
46
43
|
def values
|
47
44
|
@values ||= self == Enum ? nil : begin
|
48
|
-
|
49
|
-
conn = connection(conn_name)
|
50
|
-
conn.enum_values(type_name).freeze
|
45
|
+
connection.enum_values(type_name).freeze
|
51
46
|
end
|
52
47
|
end
|
53
48
|
|
@@ -110,8 +105,8 @@ module Torque
|
|
110
105
|
end
|
111
106
|
|
112
107
|
# Get a connection based on its name
|
113
|
-
def connection
|
114
|
-
ActiveRecord::Base.
|
108
|
+
def connection
|
109
|
+
::ActiveRecord::Base.connection
|
115
110
|
end
|
116
111
|
|
117
112
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Attributes
|
@@ -30,7 +32,7 @@ module Torque
|
|
30
32
|
def include_on(klass, method_name = nil)
|
31
33
|
method_name ||= Torque::PostgreSQL.config.enum.set_method
|
32
34
|
Builder.include_on(klass, method_name, Builder::Enum, set_features: true) do |builder|
|
33
|
-
defined_enums[builder.attribute.
|
35
|
+
defined_enums[builder.attribute.to_s] = builder.subtype
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
@@ -1,35 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module AutosaveAssociation
|
4
6
|
module ClassMethods
|
7
|
+
# Since belongs to many is a collection, the callback would normally go
|
8
|
+
# to +after_create+. However, since it is a +belongs_to+ kind of
|
9
|
+
# association, it neds to be executed +before_save+
|
5
10
|
def add_autosave_association_callbacks(reflection)
|
6
11
|
return super unless reflection.macro.eql?(:belongs_to_many)
|
7
12
|
|
8
13
|
save_method = :"autosave_associated_records_for_#{reflection.name}"
|
9
|
-
define_non_cyclic_method(save_method)
|
10
|
-
|
11
|
-
|
12
|
-
after_save(:after_save_collection_association) if ::ActiveRecord::Base
|
13
|
-
.instance_methods.include?(:after_save_collection_association)
|
14
|
+
define_non_cyclic_method(save_method) do
|
15
|
+
save_belongs_to_many_association(reflection)
|
16
|
+
end
|
14
17
|
|
15
|
-
|
16
|
-
before_update(save_method)
|
18
|
+
before_save(save_method)
|
17
19
|
|
18
20
|
define_autosave_validation_callbacks(reflection)
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
+
# Ensure the right way to execute +save_collection_association+ and also
|
25
|
+
# keep it as a single change using +build_changes+
|
26
|
+
def save_belongs_to_many_association(reflection)
|
27
|
+
previously_new_record_before_save = (@new_record_before_save ||= false)
|
28
|
+
@new_record_before_save = new_record?
|
24
29
|
|
25
30
|
association = association_instance_get(reflection.name)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
records = association.target.each_with_object(klass_attr)
|
32
|
-
write_attribute(source_attr, records.map(&:read_attribute).compact)
|
31
|
+
association&.build_changes { save_collection_association(reflection) }
|
32
|
+
rescue ::ActiveRecord::RecordInvalid
|
33
|
+
throw(:abort)
|
34
|
+
ensure
|
35
|
+
@new_record_before_save = previously_new_record_before_save
|
33
36
|
end
|
34
37
|
end
|
35
38
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Base
|
@@ -198,11 +200,18 @@ module Torque
|
|
198
200
|
# belongs_to_many :tags, dependent: :nullify
|
199
201
|
# belongs_to_many :tags, required: true, touch: true
|
200
202
|
# belongs_to_many :tags, default: -> { Tag.default }
|
201
|
-
def belongs_to_many(name, scope = nil, **options)
|
202
|
-
|
203
|
+
def belongs_to_many(name, scope = nil, **options, &extension)
|
204
|
+
klass = Associations::Builder::BelongsToMany
|
205
|
+
reflection = klass.build(self, name, scope, options, &extension)
|
203
206
|
::ActiveRecord::Reflection.add_reflection(self, name, reflection)
|
204
207
|
end
|
205
208
|
|
209
|
+
# Allow extra keyword arguments to be sent to +InsertAll+
|
210
|
+
def upsert_all(attributes, **xargs)
|
211
|
+
xargs = xargs.merge(on_duplicate: :update)
|
212
|
+
::ActiveRecord::InsertAll.new(self, attributes, **xargs).execute
|
213
|
+
end
|
214
|
+
|
206
215
|
protected
|
207
216
|
|
208
217
|
# Allow optional select attributes to be loaded manually when they are
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
module Coder
|
@@ -8,7 +10,7 @@ module Torque
|
|
8
10
|
class << self
|
9
11
|
|
10
12
|
NEED_QUOTE_FOR = /[\\"(){}, \t\n\r\v\f]/m
|
11
|
-
DELIMITER = ','
|
13
|
+
DELIMITER = ','
|
12
14
|
|
13
15
|
# This method replace the +read_array+ method from PG gem
|
14
16
|
# See https://github.com/ged/ruby-pg/blob/master/ext/pg_text_decoder.c#L177
|
@@ -32,7 +34,7 @@ module Torque
|
|
32
34
|
quoted = 0
|
33
35
|
escaped = false
|
34
36
|
result = []
|
35
|
-
part =
|
37
|
+
part = String.new
|
36
38
|
|
37
39
|
# Always start getting the non-collection character, the second char
|
38
40
|
stream.getc if stream.pos == 0
|
@@ -59,7 +61,7 @@ module Torque
|
|
59
61
|
|
60
62
|
escaped = false
|
61
63
|
quoted = 0
|
62
|
-
part =
|
64
|
+
part = String.new
|
63
65
|
|
64
66
|
when c == '"'
|
65
67
|
quoted = 1
|
@@ -1,7 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Torque
|
2
4
|
module PostgreSQL
|
3
5
|
include ActiveSupport::Configurable
|
4
6
|
|
7
|
+
# Stores a version check for compatibility purposes
|
8
|
+
AR610 = (ActiveRecord.gem_version >= Gem::Version.new('6.1.0'))
|
9
|
+
|
5
10
|
# Use the same logger as the Active Record one
|
6
11
|
def self.logger
|
7
12
|
ActiveRecord::Base.logger
|