torque-postgresql 1.1.8 → 2.0.0
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 +0 -2
- data/lib/torque/postgresql/adapter.rb +0 -1
- data/lib/torque/postgresql/adapter/database_statements.rb +4 -15
- data/lib/torque/postgresql/adapter/schema_creation.rb +13 -23
- data/lib/torque/postgresql/adapter/schema_definitions.rb +7 -21
- data/lib/torque/postgresql/adapter/schema_dumper.rb +71 -11
- data/lib/torque/postgresql/adapter/schema_statements.rb +2 -12
- data/lib/torque/postgresql/associations.rb +0 -3
- data/lib/torque/postgresql/associations/association.rb +0 -4
- data/lib/torque/postgresql/associations/association_scope.rb +18 -60
- data/lib/torque/postgresql/associations/belongs_to_many_association.rb +12 -15
- data/lib/torque/postgresql/associations/preloader.rb +0 -32
- data/lib/torque/postgresql/associations/preloader/association.rb +13 -10
- data/lib/torque/postgresql/autosave_association.rb +4 -4
- data/lib/torque/postgresql/auxiliary_statement.rb +1 -13
- data/lib/torque/postgresql/coder.rb +1 -2
- data/lib/torque/postgresql/config.rb +0 -6
- data/lib/torque/postgresql/inheritance.rb +13 -17
- data/lib/torque/postgresql/reflection/abstract_reflection.rb +19 -25
- data/lib/torque/postgresql/reflection/belongs_to_many_reflection.rb +4 -38
- data/lib/torque/postgresql/relation.rb +11 -16
- data/lib/torque/postgresql/relation/auxiliary_statement.rb +2 -8
- data/lib/torque/postgresql/relation/distinct_on.rb +1 -1
- data/lib/torque/postgresql/version.rb +1 -1
- data/spec/en.yml +19 -0
- data/spec/factories/authors.rb +6 -0
- data/spec/factories/comments.rb +13 -0
- data/spec/factories/posts.rb +6 -0
- data/spec/factories/tags.rb +5 -0
- data/spec/factories/texts.rb +5 -0
- data/spec/factories/users.rb +6 -0
- data/spec/factories/videos.rb +5 -0
- data/spec/mocks/cache_query.rb +16 -0
- data/spec/mocks/create_table.rb +35 -0
- data/spec/models/activity.rb +3 -0
- data/spec/models/activity_book.rb +4 -0
- data/spec/models/activity_post.rb +7 -0
- data/spec/models/activity_post/sample.rb +4 -0
- data/spec/models/author.rb +4 -0
- data/spec/models/author_journalist.rb +4 -0
- data/spec/models/comment.rb +3 -0
- data/spec/models/course.rb +2 -0
- data/spec/models/geometry.rb +2 -0
- data/spec/models/guest_comment.rb +4 -0
- data/spec/models/post.rb +6 -0
- data/spec/models/tag.rb +2 -0
- data/spec/models/text.rb +2 -0
- data/spec/models/time_keeper.rb +2 -0
- data/spec/models/user.rb +8 -0
- data/spec/models/video.rb +2 -0
- data/spec/schema.rb +141 -0
- data/spec/spec_helper.rb +59 -0
- data/spec/tests/arel_spec.rb +72 -0
- data/spec/tests/auxiliary_statement_spec.rb +593 -0
- data/spec/tests/belongs_to_many_spec.rb +240 -0
- data/spec/tests/coder_spec.rb +367 -0
- data/spec/tests/collector_spec.rb +59 -0
- data/spec/tests/distinct_on_spec.rb +65 -0
- data/spec/tests/enum_set_spec.rb +306 -0
- data/spec/tests/enum_spec.rb +621 -0
- data/spec/tests/geometric_builder_spec.rb +221 -0
- data/spec/tests/has_many_spec.rb +390 -0
- data/spec/tests/interval_spec.rb +167 -0
- data/spec/tests/lazy_spec.rb +24 -0
- data/spec/tests/period_spec.rb +954 -0
- data/spec/tests/quoting_spec.rb +24 -0
- data/spec/tests/range_spec.rb +36 -0
- data/spec/tests/relation_spec.rb +57 -0
- data/spec/tests/table_inheritance_spec.rb +403 -0
- metadata +103 -15
- data/lib/torque/postgresql/associations/join_dependency/join_association.rb +0 -15
- data/lib/torque/postgresql/schema_dumper.rb +0 -101
@@ -1,33 +1 @@
|
|
1
1
|
require_relative 'preloader/association'
|
2
|
-
|
3
|
-
unless Torque::PostgreSQL::AR521
|
4
|
-
module Torque
|
5
|
-
module PostgreSQL
|
6
|
-
module Associations
|
7
|
-
module Preloader
|
8
|
-
class BelongsToMany < ::ActiveRecord::Associations::Preloader::HasMany
|
9
|
-
def association_key_name
|
10
|
-
reflection.active_record_primary_key
|
11
|
-
end
|
12
|
-
|
13
|
-
def owner_key_name
|
14
|
-
reflection.foreign_key
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def preloader_for(reflection, owners, *)
|
19
|
-
return AlreadyLoaded \
|
20
|
-
if owners.first.association(reflection.name).loaded?
|
21
|
-
|
22
|
-
return BelongsToMany \
|
23
|
-
if reflection.macro.eql?(:belongs_to_many)
|
24
|
-
|
25
|
-
super
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
::ActiveRecord::Associations::Preloader.prepend(Preloader)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
@@ -8,7 +8,7 @@ module Torque
|
|
8
8
|
|
9
9
|
# For reflections connected through an array, make sure to properly
|
10
10
|
# decuple the list of ids and set them as associated with the owner
|
11
|
-
def run
|
11
|
+
def run
|
12
12
|
return super unless connected_through_array?
|
13
13
|
send("run_array_for_#{@reflection.macro}")
|
14
14
|
end
|
@@ -18,7 +18,7 @@ module Torque
|
|
18
18
|
# Specific run for belongs_many association
|
19
19
|
def run_array_for_belongs_to_many
|
20
20
|
# Add reverse to has_many
|
21
|
-
records =
|
21
|
+
records = groupped_records
|
22
22
|
owners.each do |owner|
|
23
23
|
items = records.values_at(*Array.wrap(owner[owner_key_name]))
|
24
24
|
associate_records_to_owner(owner, items.flatten)
|
@@ -29,11 +29,10 @@ module Torque
|
|
29
29
|
def run_array_for_has_many
|
30
30
|
# Add reverse to belongs_to_many
|
31
31
|
records = Hash.new { |h, k| h[k] = [] }
|
32
|
-
|
32
|
+
groupped_records.each do |ids, record|
|
33
33
|
ids.each { |id| records[id].concat(Array.wrap(record)) }
|
34
34
|
end
|
35
35
|
|
36
|
-
records.default_proc = nil
|
37
36
|
owners.each do |owner|
|
38
37
|
associate_records_to_owner(owner, records[owner[owner_key_name]] || [])
|
39
38
|
end
|
@@ -48,14 +47,18 @@ module Torque
|
|
48
47
|
scope.where(condition).load(&block)
|
49
48
|
end
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
50
|
+
def associate_records_to_owner(owner, records)
|
51
|
+
return super unless connected_through_array?
|
52
|
+
association = owner.association(reflection.name)
|
53
|
+
association.loaded!
|
54
|
+
association.target.concat(records)
|
57
55
|
end
|
58
56
|
|
57
|
+
def groupped_records
|
58
|
+
preloaded_records.group_by do |record|
|
59
|
+
convert_key(record[association_key_name])
|
60
|
+
end
|
61
|
+
end
|
59
62
|
end
|
60
63
|
|
61
64
|
::ActiveRecord::Associations::Preloader::Association.prepend(Association)
|
@@ -25,11 +25,11 @@ module Torque
|
|
25
25
|
association = association_instance_get(reflection.name)
|
26
26
|
return unless association
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
klass_fk = reflection.foreign_key
|
29
|
+
acpk = reflection.active_record_primary_key
|
30
30
|
|
31
|
-
records = association.target.each_with_object(
|
32
|
-
write_attribute(
|
31
|
+
records = association.target.each_with_object(klass_fk)
|
32
|
+
write_attribute(acpk, records.map(&:read_attribute).compact)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -211,19 +211,7 @@ module Torque
|
|
211
211
|
foreign_table = ::Arel::Table.new(association.plural_name)
|
212
212
|
end
|
213
213
|
|
214
|
-
|
215
|
-
# Possibilities:
|
216
|
-
# table
|
217
|
-
# table, foreign_klass
|
218
|
-
# table, foreign_table, foreign_klass
|
219
|
-
if association.respond_to?(:join_scope)
|
220
|
-
arity = association.method(:join_scope).arity
|
221
|
-
args = [@query.arel_table, foreign_table, base]
|
222
|
-
args.delete_at(1) if arity <= 2 # Delete foreign_table
|
223
|
-
args.delete_at(1) if arity <= 1 # Delete base (foreign_klass)
|
224
|
-
|
225
|
-
@query.merge(association.join_scope(*args))
|
226
|
-
end
|
214
|
+
@query.merge(association.join_scope(@query.arel_table, foreign_table, base))
|
227
215
|
|
228
216
|
# Add the join constraints
|
229
217
|
constraint = association.build_join_constraint(table, foreign_table)
|
@@ -2,12 +2,6 @@ module Torque
|
|
2
2
|
module PostgreSQL
|
3
3
|
include ActiveSupport::Configurable
|
4
4
|
|
5
|
-
# Stores a version check for compatibility purposes
|
6
|
-
AR510 = (ActiveRecord.gem_version >= Gem::Version.new('5.1.0'))
|
7
|
-
AR520 = (ActiveRecord.gem_version >= Gem::Version.new('5.2.0'))
|
8
|
-
AR521 = (ActiveRecord.gem_version >= Gem::Version.new('5.2.1'))
|
9
|
-
AR523 = (ActiveRecord.gem_version >= Gem::Version.new('5.2.3'))
|
10
|
-
|
11
5
|
# Use the same logger as the Active Record one
|
12
6
|
def self.logger
|
13
7
|
ActiveRecord::Base.logger
|
@@ -18,14 +18,7 @@ module Torque
|
|
18
18
|
klass.find(self.id)
|
19
19
|
end
|
20
20
|
|
21
|
-
private
|
22
|
-
|
23
|
-
def using_single_table_inheritance?(record) # :nodoc:
|
24
|
-
self.class.physically_inherited? || super
|
25
|
-
end
|
26
|
-
|
27
21
|
module ClassMethods
|
28
|
-
|
29
22
|
delegate :_auto_cast_attribute, :_record_class_attribute, to: ActiveRecord::Relation
|
30
23
|
|
31
24
|
# Get a full list of all attributes from a model and all its dependents
|
@@ -101,9 +94,10 @@ module Torque
|
|
101
94
|
|
102
95
|
# Get the final decorated table, regardless of any special condition
|
103
96
|
def decorated_table_name
|
104
|
-
|
105
|
-
|
106
|
-
contained =
|
97
|
+
parent_class = try(:module_parent) || try(:parent)
|
98
|
+
if parent_class < Base && !parent_class.abstract_class?
|
99
|
+
contained = parent_class.table_name
|
100
|
+
contained = contained.singularize if parent_class.pluralize_table_names
|
107
101
|
contained += "_"
|
108
102
|
end
|
109
103
|
|
@@ -144,17 +138,19 @@ module Torque
|
|
144
138
|
|
145
139
|
private
|
146
140
|
|
147
|
-
def
|
141
|
+
def instantiate_instance_of(klass, attributes, column_types = {}, &block)
|
142
|
+
return super unless klass.physically_inheritances?
|
143
|
+
|
148
144
|
auto_cast = _auto_cast_attribute.to_s
|
149
145
|
record_class = _record_class_attribute.to_s
|
146
|
+
return super unless attributes.key?(record_class) &&
|
147
|
+
attributes.delete(auto_cast) && attributes[record_class] != table_name
|
150
148
|
|
151
|
-
|
152
|
-
|
149
|
+
klass = casted_dependents[attributes[record_class]]
|
150
|
+
raise_unable_to_cast(attributes[record_class]) if klass.nil?
|
151
|
+
filter_attributes_for_cast(attributes, klass)
|
153
152
|
|
154
|
-
klass
|
155
|
-
raise_unable_to_cast(record[record_class]) if klass.nil?
|
156
|
-
filter_attributes_for_cast(record, klass)
|
157
|
-
klass
|
153
|
+
super(klass, attributes, column_types, &block)
|
158
154
|
end
|
159
155
|
|
160
156
|
# Filter the record attributes to be loaded to not included those from
|
@@ -12,28 +12,21 @@ module Torque
|
|
12
12
|
false
|
13
13
|
end
|
14
14
|
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
klass_scope = klass_join_scope(table, predicate_builder)
|
29
|
-
|
30
|
-
klass_scope.where!(build_id_constraint_between(table, foreign_table))
|
31
|
-
klass_scope.where!(type => foreign_klass.polymorphic_name) if type
|
32
|
-
klass_scope.where!(klass.send(:type_condition, table)) \
|
33
|
-
if klass.finder_needs_type_condition?
|
15
|
+
# Fix where the join_scope method is the one now responsible for
|
16
|
+
# building the join condition
|
17
|
+
def join_scope(table, foreign_table, foreign_klass)
|
18
|
+
return super unless connected_through_array?
|
19
|
+
|
20
|
+
predicate_builder = predicate_builder(table)
|
21
|
+
scope_chain_items = join_scopes(table, predicate_builder)
|
22
|
+
klass_scope = klass_join_scope(table, predicate_builder)
|
23
|
+
|
24
|
+
klass_scope.where!(build_id_constraint_between(table, foreign_table))
|
25
|
+
klass_scope.where!(type => foreign_klass.polymorphic_name) if type
|
26
|
+
klass_scope.where!(klass.send(:type_condition, table)) \
|
27
|
+
if klass.finder_needs_type_condition?
|
34
28
|
|
35
|
-
|
36
|
-
end
|
29
|
+
scope_chain_items.inject(klass_scope, &:merge!)
|
37
30
|
end
|
38
31
|
|
39
32
|
# Manually build the join constraint
|
@@ -50,9 +43,9 @@ module Torque
|
|
50
43
|
return klass_attr.eq(source_attr) unless connected_through_array?
|
51
44
|
|
52
45
|
# Klass and key are associated with the reflection Class
|
53
|
-
klass_type = klass.columns_hash[
|
46
|
+
klass_type = klass.columns_hash[join_keys.key.to_s]
|
54
47
|
# active_record and foreign_key are associated with the source Class
|
55
|
-
source_type = active_record.columns_hash[
|
48
|
+
source_type = active_record.columns_hash[join_keys.foreign_key.to_s]
|
56
49
|
|
57
50
|
# If both are attributes but the left side is not an array, and the
|
58
51
|
# right side is, use the ANY operation
|
@@ -78,8 +71,8 @@ module Torque
|
|
78
71
|
private
|
79
72
|
|
80
73
|
def build_id_constraint_between(table, foreign_table)
|
81
|
-
klass_attr = table[
|
82
|
-
source_attr = foreign_table[
|
74
|
+
klass_attr = table[join_keys.key.to_s]
|
75
|
+
source_attr = foreign_table[join_keys.foreign_key.to_s]
|
83
76
|
|
84
77
|
build_id_constraint(klass_attr, source_attr)
|
85
78
|
end
|
@@ -105,6 +98,7 @@ module Torque
|
|
105
98
|
# returns either +nil+ or the inverse association name that it finds.
|
106
99
|
def automatic_inverse_of
|
107
100
|
return super unless connected_through_array?
|
101
|
+
|
108
102
|
if can_find_inverse_of_automatically?(self)
|
109
103
|
inverse_name = options[:as] || active_record.name.demodulize
|
110
104
|
inverse_name = ActiveSupport::Inflector.underscore(inverse_name)
|
@@ -10,10 +10,6 @@ module Torque
|
|
10
10
|
true
|
11
11
|
end
|
12
12
|
|
13
|
-
def belongs_to?
|
14
|
-
true
|
15
|
-
end
|
16
|
-
|
17
13
|
def collection?
|
18
14
|
true
|
19
15
|
end
|
@@ -23,7 +19,7 @@ module Torque
|
|
23
19
|
end
|
24
20
|
|
25
21
|
def foreign_key
|
26
|
-
@foreign_key ||= options[:
|
22
|
+
@foreign_key ||= options[:primary_key] || derive_foreign_key.freeze
|
27
23
|
end
|
28
24
|
|
29
25
|
def association_foreign_key
|
@@ -31,46 +27,16 @@ module Torque
|
|
31
27
|
end
|
32
28
|
|
33
29
|
def active_record_primary_key
|
34
|
-
@active_record_primary_key ||= options[:
|
35
|
-
end
|
36
|
-
|
37
|
-
unless PostgreSQL::AR510
|
38
|
-
def join_keys(*)
|
39
|
-
JoinKeys.new(join_pk, join_fk)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
if PostgreSQL::AR520
|
44
|
-
def join_primary_key(*)
|
45
|
-
active_record_primary_key
|
46
|
-
end
|
47
|
-
|
48
|
-
def join_foreign_key
|
49
|
-
foreign_key
|
50
|
-
end
|
51
|
-
else
|
52
|
-
def join_id_for(owner)
|
53
|
-
owner[foreign_key]
|
54
|
-
end
|
30
|
+
@active_record_primary_key ||= options[:foreign_key] || derive_primary_key
|
55
31
|
end
|
56
32
|
|
57
33
|
private
|
58
34
|
|
59
|
-
|
60
|
-
def join_pk(*)
|
61
|
-
active_record_primary_key
|
62
|
-
end
|
63
|
-
|
64
|
-
def join_fk
|
65
|
-
foreign_key
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def derive_primary_key
|
35
|
+
def derive_foreign_key
|
70
36
|
klass.primary_key
|
71
37
|
end
|
72
38
|
|
73
|
-
def
|
39
|
+
def derive_primary_key
|
74
40
|
"#{name.to_s.singularize}_ids"
|
75
41
|
end
|
76
42
|
end
|
@@ -52,11 +52,8 @@ module Torque
|
|
52
52
|
when Array
|
53
53
|
resolve_column(item, base)
|
54
54
|
when Hash
|
55
|
-
raise ArgumentError,
|
56
|
-
item.map
|
57
|
-
other_list = [other_list] unless other_list.kind_of? Enumerable
|
58
|
-
resolve_column(other_list, key)
|
59
|
-
end
|
55
|
+
raise ArgumentError, 'Unsupported Hash for attributes on third level' if base
|
56
|
+
item.map { |key, other_list| resolve_column(Array.wrap(other_list), key) }
|
60
57
|
else
|
61
58
|
raise ArgumentError, "Unsupported argument type: #{value} (#{value.class})"
|
62
59
|
end
|
@@ -138,19 +135,17 @@ module Torque
|
|
138
135
|
ActiveRecord::Relation::SINGLE_VALUE_METHODS += Relation::SINGLE_VALUE_METHODS
|
139
136
|
ActiveRecord::Relation::MULTI_VALUE_METHODS += Relation::MULTI_VALUE_METHODS
|
140
137
|
ActiveRecord::Relation::VALUE_METHODS += Relation::VALUE_METHODS
|
141
|
-
ActiveRecord::QueryMethods::VALID_UNSCOPING_VALUES += [
|
142
|
-
|
138
|
+
ActiveRecord::QueryMethods::VALID_UNSCOPING_VALUES += %i[cast_records itself_only
|
139
|
+
distinct_on auxiliary_statements]
|
143
140
|
|
144
|
-
|
145
|
-
|
146
|
-
ActiveRecord::QueryMethods::DEFAULT_VALUES[value]
|
147
|
-
|
148
|
-
end
|
141
|
+
Relation::SINGLE_VALUE_METHODS.each do |value|
|
142
|
+
ActiveRecord::QueryMethods::DEFAULT_VALUES[value] = nil \
|
143
|
+
if ActiveRecord::QueryMethods::DEFAULT_VALUES[value].nil?
|
144
|
+
end
|
149
145
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
146
|
+
Relation::MULTI_VALUE_METHODS.each do |value|
|
147
|
+
ActiveRecord::QueryMethods::DEFAULT_VALUES[value] ||= \
|
148
|
+
ActiveRecord::QueryMethods::FROZEN_EMPTY_ARRAY
|
154
149
|
end
|
155
150
|
|
156
151
|
$VERBOSE = warn_level
|
@@ -33,14 +33,8 @@ module Torque
|
|
33
33
|
# Get all auxiliary statements bound attributes and the base bound
|
34
34
|
# attributes as well
|
35
35
|
def bound_attributes
|
36
|
-
|
37
|
-
|
38
|
-
visitor.accept(self.arel.ast, ::Arel::Collectors::Bind.new).value
|
39
|
-
else
|
40
|
-
return super unless self.auxiliary_statements_values.present?
|
41
|
-
bindings = self.auxiliary_statements_values.map(&:bound_attributes)
|
42
|
-
(bindings + super).flatten
|
43
|
-
end
|
36
|
+
visitor = ::Arel::Visitors::PostgreSQL.new(ActiveRecord::Base.connection)
|
37
|
+
visitor.accept(self.arel.ast, ::Arel::Collectors::Bind.new).value
|
44
38
|
end
|
45
39
|
|
46
40
|
private
|
@@ -33,7 +33,7 @@ module Torque
|
|
33
33
|
|
34
34
|
# Hook arel build to add the distinct on clause
|
35
35
|
def build_arel(*)
|
36
|
-
arel =
|
36
|
+
arel = super
|
37
37
|
value = self.distinct_on_values
|
38
38
|
arel.distinct_on(resolve_column(value)) if value.present?
|
39
39
|
arel
|
data/spec/en.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
en:
|
2
|
+
torque: 'Torque Rocks!'
|
3
|
+
activerecord:
|
4
|
+
attributes:
|
5
|
+
user:
|
6
|
+
role:
|
7
|
+
visitor: 'A simple Visitor'
|
8
|
+
role:
|
9
|
+
assistant: 'An Assistant'
|
10
|
+
enums:
|
11
|
+
content_status:
|
12
|
+
created: '1 - Created'
|
13
|
+
roles:
|
14
|
+
manager: 'The Manager'
|
15
|
+
enum:
|
16
|
+
content_status:
|
17
|
+
draft: 'Draft (2)'
|
18
|
+
published: 'Finally published'
|
19
|
+
admin: 'Super Duper Admin'
|