torque-postgresql 1.1.0 → 1.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/associations/association_scope.rb +1 -0
- data/lib/torque/postgresql/attributes.rb +0 -16
- data/lib/torque/postgresql/attributes/builder.rb +2 -2
- data/lib/torque/postgresql/attributes/builder/enum.rb +103 -66
- data/lib/torque/postgresql/attributes/builder/period.rb +1 -1
- data/lib/torque/postgresql/attributes/enum.rb +6 -1
- data/lib/torque/postgresql/attributes/enum_set.rb +6 -3
- data/lib/torque/postgresql/auxiliary_statement.rb +9 -2
- data/lib/torque/postgresql/config.rb +10 -0
- data/lib/torque/postgresql/reflection/abstract_reflection.rb +27 -4
- data/lib/torque/postgresql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b95a55ebfe82e5b96582da09307f1d45d62ba922
|
4
|
+
data.tar.gz: 38a068ec3fa7cc5aab2425a31e8ed37a49b15132
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b708c73cfcac1798474e35099570e4def16a6a51b2448ef34ce2ec5e97dd4c8d57f48fa51f18182f0405afa7eed1884b81846cb3b2e132b638c8711ee80dd72c
|
7
|
+
data.tar.gz: 7bab6bd30e0b3898826b20cce99ff629192ea62d772864e10a3fc141e86e5f3f27a0f9e459addc29a8a27bcbb7df17920831d0f7e7b01ac823d65f600b699530
|
@@ -4,19 +4,3 @@ require_relative 'attributes/builder'
|
|
4
4
|
require_relative 'attributes/enum'
|
5
5
|
require_relative 'attributes/enum_set'
|
6
6
|
require_relative 'attributes/period'
|
7
|
-
|
8
|
-
module Torque
|
9
|
-
module PostgreSQL
|
10
|
-
module Attributes
|
11
|
-
extend ActiveSupport::Concern
|
12
|
-
|
13
|
-
# Configure enum_save_on_bang behavior
|
14
|
-
included do
|
15
|
-
class_attribute :enum_save_on_bang, instance_accessor: true
|
16
|
-
self.enum_save_on_bang = Torque::PostgreSQL.config.enum.save_on_bang
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
ActiveRecord::Base.include Attributes
|
21
|
-
end
|
22
|
-
end
|
@@ -5,14 +5,14 @@ module Torque
|
|
5
5
|
module PostgreSQL
|
6
6
|
module Attributes
|
7
7
|
module Builder
|
8
|
-
def self.include_on(klass, method_name, builder_klass, &block)
|
8
|
+
def self.include_on(klass, method_name, builder_klass, **extra, &block)
|
9
9
|
klass.define_singleton_method(method_name) do |*args, **options|
|
10
10
|
return unless connection.table_exists?(table_name)
|
11
11
|
|
12
12
|
args.each do |attribute|
|
13
13
|
begin
|
14
14
|
# Generate methods on self class
|
15
|
-
builder = builder_klass.new(self, attribute, options)
|
15
|
+
builder = builder_klass.new(self, attribute, extra.merge(options))
|
16
16
|
builder.conflicting?
|
17
17
|
builder.build
|
18
18
|
|
@@ -5,7 +5,8 @@ module Torque
|
|
5
5
|
class Enum
|
6
6
|
VALID_TYPES = %i[enum enum_set].freeze
|
7
7
|
|
8
|
-
attr_accessor :klass, :attribute, :subtype, :options, :values,
|
8
|
+
attr_accessor :klass, :attribute, :subtype, :options, :values,
|
9
|
+
:klass_module, :instance_module
|
9
10
|
|
10
11
|
# Start a new builder of methods for enum values on ActiveRecord::Base
|
11
12
|
def initialize(klass, attribute, options)
|
@@ -40,15 +41,20 @@ module Torque
|
|
40
41
|
|
41
42
|
@values_methods = begin
|
42
43
|
values.map do |val|
|
43
|
-
|
44
|
-
scope = base %
|
44
|
+
key = val.downcase.tr('- ', '__')
|
45
|
+
scope = base % key
|
45
46
|
ask = scope + '?'
|
46
47
|
bang = scope + '!'
|
47
|
-
[
|
48
|
+
[key, [scope, ask, bang, val]]
|
48
49
|
end.to_h
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
53
|
+
# Check if it's building the methods for sets
|
54
|
+
def set_features?
|
55
|
+
options[:set_features].present?
|
56
|
+
end
|
57
|
+
|
52
58
|
# Check if any of the methods that will be created get in conflict
|
53
59
|
# with the base class methods
|
54
60
|
def conflicting?
|
@@ -56,12 +62,20 @@ module Torque
|
|
56
62
|
attributes = attribute.pluralize
|
57
63
|
|
58
64
|
dangerous?(attributes, true)
|
59
|
-
dangerous?("#{attributes}
|
65
|
+
dangerous?("#{attributes}_keys", true)
|
60
66
|
dangerous?("#{attributes}_texts", true)
|
67
|
+
dangerous?("#{attributes}_options", true)
|
61
68
|
dangerous?("#{attribute}_text")
|
62
69
|
|
63
|
-
|
64
|
-
|
70
|
+
if set_features?
|
71
|
+
dangerous?("has_#{attributes}", true)
|
72
|
+
dangerous?("has_any_#{attributes}", true)
|
73
|
+
end
|
74
|
+
|
75
|
+
values_methods.each do |attr, (scope, ask, bang, *)|
|
76
|
+
dangerous?(scope, true)
|
77
|
+
dangerous?(bang)
|
78
|
+
dangerous?(ask)
|
65
79
|
end
|
66
80
|
rescue Interrupt => err
|
67
81
|
raise ArgumentError, <<-MSG.squish
|
@@ -73,14 +87,16 @@ module Torque
|
|
73
87
|
|
74
88
|
# Create all methods needed
|
75
89
|
def build
|
76
|
-
@
|
90
|
+
@klass_module = Module.new
|
91
|
+
@instance_module = Module.new
|
77
92
|
|
78
93
|
plural
|
79
94
|
stringify
|
80
95
|
all_values
|
96
|
+
set_scopes if set_features?
|
81
97
|
|
82
|
-
klass.
|
83
|
-
klass.
|
98
|
+
klass.extend klass_module
|
99
|
+
klass.include instance_module
|
84
100
|
end
|
85
101
|
|
86
102
|
private
|
@@ -96,78 +112,99 @@ module Torque
|
|
96
112
|
raise Interrupt, method_name.to_s
|
97
113
|
end
|
98
114
|
end
|
115
|
+
rescue Interrupt => e
|
116
|
+
raise e if Torque::PostgreSQL.config.enum.raise_conflicting
|
117
|
+
type = class_method ? 'class method' : 'instance method'
|
118
|
+
indicator = class_method ? '.' : '#'
|
119
|
+
|
120
|
+
Torque::PostgreSQL.logger.info(<<~MSG.squish)
|
121
|
+
Creating #{class_method} :#{method_name} for enum.
|
122
|
+
Overwriting existing method #{klass.name}#{indicator}#{method_name}.
|
123
|
+
MSG
|
99
124
|
end
|
100
125
|
|
101
126
|
# Create the method that allow access to the list of values
|
102
127
|
def plural
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
128
|
+
enum_klass = subtype.klass.name
|
129
|
+
klass_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
130
|
+
def #{attribute.pluralize} # def roles
|
131
|
+
::#{enum_klass}.values # Enum::Roles.values
|
132
|
+
end # end
|
133
|
+
|
134
|
+
def #{attribute.pluralize}_keys # def roles_keys
|
135
|
+
::#{enum_klass}.keys # Enum::Roles.keys
|
136
|
+
end # end
|
137
|
+
|
138
|
+
def #{attribute.pluralize}_texts # def roles_texts
|
139
|
+
::#{enum_klass}.members.map do |member| # Enum::Roles.members do |member|
|
140
|
+
member.text('#{attribute}', self) # member.text('role', self)
|
141
|
+
end # end
|
142
|
+
end # end
|
143
|
+
|
144
|
+
def #{attribute.pluralize}_options # def roles_options
|
145
|
+
#{attribute.pluralize}_texts.zip(::#{enum_klass}.values) # roles_texts.zip(Enum::Roles.values)
|
146
|
+
end # end
|
147
|
+
RUBY
|
148
|
+
end
|
120
149
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
150
|
+
# Create additional methods when the enum is a set, which needs
|
151
|
+
# better ways to check if values are present or not
|
152
|
+
def set_scopes
|
153
|
+
cast_type = subtype.name.chomp('[]')
|
154
|
+
klass_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
155
|
+
def has_#{attribute.pluralize}(*values) # def has_roles(*values)
|
156
|
+
attr = arel_attribute('#{attribute}') # attr = arel_attribute('role')
|
157
|
+
where(attr.contains(::Arel.array(values, cast: '#{cast_type}'))) # where(attr.contains(::Arel.array(values, cast: 'roles')))
|
158
|
+
end # end
|
159
|
+
|
160
|
+
def has_any_#{attribute.pluralize}(*values) # def has_roles(*values)
|
161
|
+
attr = arel_attribute('#{attribute}') # attr = arel_attribute('role')
|
162
|
+
where(attr.overlaps(::Arel.array(values, cast: '#{cast_type}'))) # where(attr.overlaps(::Arel.array(values, cast: 'roles')))
|
163
|
+
end # end
|
164
|
+
RUBY
|
126
165
|
end
|
127
166
|
|
128
167
|
# Create the method that turn the attribute value into text using
|
129
168
|
# the model scope
|
130
169
|
def stringify
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
define_method("#{attr}_text") { send(attr)&.text(attr, self) }
|
137
|
-
end
|
170
|
+
instance_module.module_eval <<-RUBY, __FILE__, __LINE__ + 1
|
171
|
+
def #{attribute}_text # def role_text
|
172
|
+
#{attribute}.text('#{attribute}', self) # role.text('role', self)
|
173
|
+
end # end
|
174
|
+
RUBY
|
138
175
|
end
|
139
176
|
|
140
177
|
# Create all the methods that represent actions related to the
|
141
178
|
# attribute value
|
142
179
|
def all_values
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
#
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
true
|
168
|
-
end
|
169
|
-
end
|
180
|
+
klass_content = ''
|
181
|
+
instance_content = ''
|
182
|
+
enum_klass = subtype.klass.name
|
183
|
+
|
184
|
+
values_methods.each do |key, (scope, ask, bang, val)|
|
185
|
+
klass_content += <<-RUBY
|
186
|
+
def #{scope} # def admin
|
187
|
+
attr = arel_attribute('#{attribute}') # attr = arel_attribute('role')
|
188
|
+
where(::#{enum_klass}.scope(attr, '#{val}')) # where(Enum::Roles.scope(attr, 'admin'))
|
189
|
+
end # end
|
190
|
+
RUBY
|
191
|
+
|
192
|
+
instance_content += <<-RUBY
|
193
|
+
def #{ask} # def admin?
|
194
|
+
#{attribute}.#{key}? # role.admin?
|
195
|
+
end # end
|
196
|
+
|
197
|
+
def #{bang} # admin!
|
198
|
+
self.#{attribute} = '#{val}' # self.role = 'admin'
|
199
|
+
return unless #{attribute}_changed? # return unless role_changed?
|
200
|
+
return save! if Torque::PostgreSQL.config.enum.save_on_bang
|
201
|
+
true # true
|
202
|
+
end # end
|
203
|
+
RUBY
|
170
204
|
end
|
205
|
+
|
206
|
+
klass_module.module_eval(klass_content)
|
207
|
+
instance_module.module_eval(instance_content)
|
171
208
|
end
|
172
209
|
end
|
173
210
|
end
|
@@ -164,7 +164,7 @@ module Torque
|
|
164
164
|
method_content = define_string_method(method_name, method_content, args)
|
165
165
|
|
166
166
|
source_module = send("#{type}_module")
|
167
|
-
source_module.
|
167
|
+
source_module.module_eval(method_content)
|
168
168
|
end
|
169
169
|
|
170
170
|
private
|
@@ -51,9 +51,14 @@ module Torque
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
+
# List of valus as symbols
|
55
|
+
def keys
|
56
|
+
values.map(&:to_sym)
|
57
|
+
end
|
58
|
+
|
54
59
|
# Different from values, it returns the list of items already casted
|
55
60
|
def members
|
56
|
-
values.
|
61
|
+
values.map(&method(:new))
|
57
62
|
end
|
58
63
|
|
59
64
|
# Get the list of the values translated by I18n
|
@@ -10,7 +10,7 @@ module Torque
|
|
10
10
|
include Enumerable
|
11
11
|
|
12
12
|
delegate :each, to: :members
|
13
|
-
delegate :values, :members, :texts, :to_options, :valid?, :size,
|
13
|
+
delegate :values, :keys, :members, :texts, :to_options, :valid?, :size,
|
14
14
|
:length, :connection_specification_name, to: :enum_source
|
15
15
|
|
16
16
|
# Find or create the class that will handle the value
|
@@ -28,7 +28,10 @@ module Torque
|
|
28
28
|
# Provide a method on the given class to setup which enum sets will be
|
29
29
|
# manually initialized
|
30
30
|
def include_on(klass, method_name = nil)
|
31
|
-
|
31
|
+
method_name ||= Torque::PostgreSQL.config.enum.set_method
|
32
|
+
Builder.include_on(klass, method_name, Builder::Enum, set_features: true) do |builder|
|
33
|
+
defined_enums[builder.attribute.to_sym] = builder.subtype
|
34
|
+
end
|
32
35
|
end
|
33
36
|
|
34
37
|
# The original Enum implementation, for individual values
|
@@ -73,7 +76,7 @@ module Torque
|
|
73
76
|
|
74
77
|
# Build an active record scope for a given atribute agains a value
|
75
78
|
def scope(attribute, value)
|
76
|
-
attribute.contains(
|
79
|
+
attribute.contains(::Arel.array(value, cast: enum_source.type_name))
|
77
80
|
end
|
78
81
|
|
79
82
|
private
|
@@ -205,9 +205,16 @@ module Torque
|
|
205
205
|
end
|
206
206
|
|
207
207
|
# Add the scopes defined by the reflection
|
208
|
+
# Possibilities:
|
209
|
+
# table
|
210
|
+
# table, foreign_klass
|
211
|
+
# table, foreign_table, foreign_klass
|
208
212
|
if association.respond_to?(:join_scope)
|
209
|
-
|
210
|
-
args
|
213
|
+
arity = association.method(:join_scope).arity
|
214
|
+
args = [@query.arel_table, foreign_table, base]
|
215
|
+
args.delete_at(1) if arity <= 2 # Delete foreign_table
|
216
|
+
args.delete_at(1) if arity <= 1 # Delete base (foreign_klass)
|
217
|
+
|
211
218
|
@query.merge(association.join_scope(*args))
|
212
219
|
end
|
213
220
|
|
@@ -4,6 +4,12 @@ module Torque
|
|
4
4
|
|
5
5
|
# Stores a version check for compatibility purposes
|
6
6
|
AR521 = (ActiveRecord.gem_version >= Gem::Version.new('5.2.1'))
|
7
|
+
AR523 = (ActiveRecord.gem_version >= Gem::Version.new('5.2.3'))
|
8
|
+
|
9
|
+
# Use the same logger as the Active Record one
|
10
|
+
def self.logger
|
11
|
+
ActiveRecord::Base.logger
|
12
|
+
end
|
7
13
|
|
8
14
|
# Allow nested configurations
|
9
15
|
# :TODO: Rely on +inheritable_copy+ to make nested configurations
|
@@ -63,6 +69,10 @@ module Torque
|
|
63
69
|
# database or not
|
64
70
|
enum.save_on_bang = true
|
65
71
|
|
72
|
+
# Indicates if it should raise errors when a generated method would
|
73
|
+
# conflict with an existing one
|
74
|
+
enum.raise_conflicting = false
|
75
|
+
|
66
76
|
# Specify the namespace of each enum type of value
|
67
77
|
enum.namespace = ::Object.const_set('Enum', Module.new)
|
68
78
|
|
@@ -17,12 +17,28 @@ module Torque
|
|
17
17
|
method(:join_keys).arity.eql?(0) ? join_keys : join_keys(klass)
|
18
18
|
end
|
19
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?
|
34
|
+
|
35
|
+
scope_chain_items.inject(klass_scope, &:merge!)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
20
39
|
# Manually build the join constraint
|
21
40
|
def build_join_constraint(table, foreign_table)
|
22
|
-
|
23
|
-
source_attr = foreign_table[torque_join_keys.foreign_key.to_s]
|
24
|
-
|
25
|
-
result = build_id_constraint(klass_attr, source_attr)
|
41
|
+
result = build_id_constraint_between(table, foreign_table)
|
26
42
|
result = table.create_and([result, klass.send(:type_condition, table)]) \
|
27
43
|
if klass.finder_needs_type_condition?
|
28
44
|
|
@@ -61,6 +77,13 @@ module Torque
|
|
61
77
|
|
62
78
|
private
|
63
79
|
|
80
|
+
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]
|
83
|
+
|
84
|
+
build_id_constraint(klass_attr, source_attr)
|
85
|
+
end
|
86
|
+
|
64
87
|
# Prepare a value for an array constraint overlap condition
|
65
88
|
def cast_constraint_to_array(type, value, should_cast)
|
66
89
|
base_ready = type.try(:array) && value.is_a?(AREL_ATTR)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: torque-postgresql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Silva
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|