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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/torque/postgresql.rb +0 -2
  3. data/lib/torque/postgresql/adapter.rb +0 -1
  4. data/lib/torque/postgresql/adapter/database_statements.rb +4 -15
  5. data/lib/torque/postgresql/adapter/schema_creation.rb +13 -23
  6. data/lib/torque/postgresql/adapter/schema_definitions.rb +7 -21
  7. data/lib/torque/postgresql/adapter/schema_dumper.rb +71 -11
  8. data/lib/torque/postgresql/adapter/schema_statements.rb +2 -12
  9. data/lib/torque/postgresql/associations.rb +0 -3
  10. data/lib/torque/postgresql/associations/association.rb +0 -4
  11. data/lib/torque/postgresql/associations/association_scope.rb +18 -60
  12. data/lib/torque/postgresql/associations/belongs_to_many_association.rb +12 -15
  13. data/lib/torque/postgresql/associations/preloader.rb +0 -32
  14. data/lib/torque/postgresql/associations/preloader/association.rb +13 -10
  15. data/lib/torque/postgresql/autosave_association.rb +4 -4
  16. data/lib/torque/postgresql/auxiliary_statement.rb +1 -13
  17. data/lib/torque/postgresql/coder.rb +1 -2
  18. data/lib/torque/postgresql/config.rb +0 -6
  19. data/lib/torque/postgresql/inheritance.rb +13 -17
  20. data/lib/torque/postgresql/reflection/abstract_reflection.rb +19 -25
  21. data/lib/torque/postgresql/reflection/belongs_to_many_reflection.rb +4 -38
  22. data/lib/torque/postgresql/relation.rb +11 -16
  23. data/lib/torque/postgresql/relation/auxiliary_statement.rb +2 -8
  24. data/lib/torque/postgresql/relation/distinct_on.rb +1 -1
  25. data/lib/torque/postgresql/version.rb +1 -1
  26. data/spec/en.yml +19 -0
  27. data/spec/factories/authors.rb +6 -0
  28. data/spec/factories/comments.rb +13 -0
  29. data/spec/factories/posts.rb +6 -0
  30. data/spec/factories/tags.rb +5 -0
  31. data/spec/factories/texts.rb +5 -0
  32. data/spec/factories/users.rb +6 -0
  33. data/spec/factories/videos.rb +5 -0
  34. data/spec/mocks/cache_query.rb +16 -0
  35. data/spec/mocks/create_table.rb +35 -0
  36. data/spec/models/activity.rb +3 -0
  37. data/spec/models/activity_book.rb +4 -0
  38. data/spec/models/activity_post.rb +7 -0
  39. data/spec/models/activity_post/sample.rb +4 -0
  40. data/spec/models/author.rb +4 -0
  41. data/spec/models/author_journalist.rb +4 -0
  42. data/spec/models/comment.rb +3 -0
  43. data/spec/models/course.rb +2 -0
  44. data/spec/models/geometry.rb +2 -0
  45. data/spec/models/guest_comment.rb +4 -0
  46. data/spec/models/post.rb +6 -0
  47. data/spec/models/tag.rb +2 -0
  48. data/spec/models/text.rb +2 -0
  49. data/spec/models/time_keeper.rb +2 -0
  50. data/spec/models/user.rb +8 -0
  51. data/spec/models/video.rb +2 -0
  52. data/spec/schema.rb +141 -0
  53. data/spec/spec_helper.rb +59 -0
  54. data/spec/tests/arel_spec.rb +72 -0
  55. data/spec/tests/auxiliary_statement_spec.rb +593 -0
  56. data/spec/tests/belongs_to_many_spec.rb +240 -0
  57. data/spec/tests/coder_spec.rb +367 -0
  58. data/spec/tests/collector_spec.rb +59 -0
  59. data/spec/tests/distinct_on_spec.rb +65 -0
  60. data/spec/tests/enum_set_spec.rb +306 -0
  61. data/spec/tests/enum_spec.rb +621 -0
  62. data/spec/tests/geometric_builder_spec.rb +221 -0
  63. data/spec/tests/has_many_spec.rb +390 -0
  64. data/spec/tests/interval_spec.rb +167 -0
  65. data/spec/tests/lazy_spec.rb +24 -0
  66. data/spec/tests/period_spec.rb +954 -0
  67. data/spec/tests/quoting_spec.rb +24 -0
  68. data/spec/tests/range_spec.rb +36 -0
  69. data/spec/tests/relation_spec.rb +57 -0
  70. data/spec/tests/table_inheritance_spec.rb +403 -0
  71. metadata +103 -15
  72. data/lib/torque/postgresql/associations/join_dependency/join_association.rb +0 -15
  73. 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(preloader)
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 = load_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
- load_records.each do |ids, record|
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
- unless Torque::PostgreSQL::AR521
52
- def associate_records_to_owner(owner, records)
53
- association = owner.association(reflection.name)
54
- association.loaded!
55
- association.target.concat(records)
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
- klass_attr = reflection.active_record_primary_key
29
- source_attr = reflection.foreign_key
28
+ klass_fk = reflection.foreign_key
29
+ acpk = reflection.active_record_primary_key
30
30
 
31
- records = association.target.each_with_object(klass_attr)
32
- write_attribute(source_attr, records.map(&:read_attribute).compact)
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
- # Add the scopes defined by the reflection
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)
@@ -3,8 +3,7 @@ module Torque
3
3
  module Coder
4
4
 
5
5
  # This class represents an Record to be encoded, instead of a literal Array
6
- class Record < Array
7
- end
6
+ Record = Class.new(Array)
8
7
 
9
8
  class << self
10
9
 
@@ -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
- if parent < Base && !parent.abstract_class?
105
- contained = parent.table_name
106
- contained = contained.singularize if parent.pluralize_table_names
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 discriminate_class_for_record(record) # :nodoc:
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
- return super unless record.key?(record_class) &&
152
- record.delete(auto_cast) && record[record_class] != table_name
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 = casted_dependents[record[record_class]]
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
- # Monkey patching for rais 5.0
16
- def torque_join_keys
17
- method(:join_keys).arity.eql?(0) ? join_keys : join_keys(klass)
18
- end
19
-
20
- # Fix for rails 5.2.3 where the join_scope method is the one now
21
- # responsible for building the join condition
22
- if Torque::PostgreSQL::AR523
23
- def join_scope(table, foreign_table, foreign_klass)
24
- return super unless connected_through_array?
25
-
26
- predicate_builder = predicate_builder(table)
27
- scope_chain_items = join_scopes(table, predicate_builder)
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
- scope_chain_items.inject(klass_scope, &:merge!)
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[torque_join_keys.key.to_s]
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[torque_join_keys.foreign_key.to_s]
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[torque_join_keys.key.to_s]
82
- source_attr = foreign_table[torque_join_keys.foreign_key.to_s]
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[:foreign_key] || derive_foreign_key.freeze
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[:primary_key] || derive_primary_key
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
- unless PostgreSQL::AR520
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 derive_foreign_key
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, "Unsupported Hash for attributes on third level" if base
56
- item.map do |key, other_list|
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 += [:cast_records, :itself_only,
142
- :distinct_on, :auxiliary_statements]
138
+ ActiveRecord::QueryMethods::VALID_UNSCOPING_VALUES += %i[cast_records itself_only
139
+ distinct_on auxiliary_statements]
143
140
 
144
- if ActiveRecord::QueryMethods.const_defined?('DEFAULT_VALUES')
145
- Relation::SINGLE_VALUE_METHODS.each do |value|
146
- ActiveRecord::QueryMethods::DEFAULT_VALUES[value] = nil \
147
- if ActiveRecord::QueryMethods::DEFAULT_VALUES[value].nil?
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
- Relation::MULTI_VALUE_METHODS.each do |value|
151
- ActiveRecord::QueryMethods::DEFAULT_VALUES[value] ||= \
152
- ActiveRecord::QueryMethods::FROZEN_EMPTY_ARRAY
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
- if Torque::PostgreSQL::AR521
37
- visitor = ::Arel::Visitors::PostgreSQL.new(ActiveRecord::Base.connection)
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 = Torque::PostgreSQL::AR521 ? super : super()
36
+ arel = super
37
37
  value = self.distinct_on_values
38
38
  arel.distinct_on(resolve_column(value)) if value.present?
39
39
  arel
@@ -1,5 +1,5 @@
1
1
  module Torque
2
2
  module PostgreSQL
3
- VERSION = '1.1.8'
3
+ VERSION = '2.0.0'
4
4
  end
5
5
  end
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'