torque-postgresql 2.0.3 → 2.1.1
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.
- 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
|