rhino_project_core 0.21.0.beta.10 → 0.21.0.beta.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rhino/resource/active_record_extension/properties_describe.rb +150 -144
- data/lib/rhino/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 48972a6d87e8a9974598926b25ef186f652203f9b1d7c53ebc9de7853f87a493
|
4
|
+
data.tar.gz: 650860cbba709f699f9cac8b63c29a4a285b4b56cb620ec13e524935798a49f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cf0499cbf1f48987e6299ea7600eace332c13cb37c10abab42d99de97aaaeedbd9b26f0c8de83cbd9a45c193ebb9124cca5aa22569c91d139c65ddaec8e057c
|
7
|
+
data.tar.gz: 026fd26d7518f039183b1510bca2328aeecaf612350ee904c823a7b5bad4a6305053d886e0fa1fe62865cb4149d0ca60c78924639e5760f185570c2f4c4725ac
|
@@ -33,194 +33,200 @@ module Rhino
|
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
def ref_descriptor(names)
|
44
|
-
{
|
45
|
-
type: :reference,
|
46
|
-
anyOf: names.map { |name| { :$ref => "#/components/schemas/#{name.singularize}" } }
|
47
|
-
}
|
48
|
-
end
|
49
|
-
|
50
|
-
def property_type_and_format_attr(name) # rubocop:todo Metrics/MethodLength
|
51
|
-
atype = attribute_types[name.to_s].type
|
52
|
-
|
53
|
-
# The PG array delegates type to "subtype" which is the actual type of the array elements
|
54
|
-
if attribute_types[name.to_s].is_a? ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array
|
55
|
-
return {
|
56
|
-
type: :array,
|
57
|
-
items: {
|
58
|
-
type: atype
|
59
|
-
}
|
60
|
-
}
|
36
|
+
# FIXME: It can be a hash if passed in from a reference which might have something like
|
37
|
+
# rhino_references %i[{blog_posts: [:comments]}]
|
38
|
+
# but I cannot find current spot where it is used like that currently
|
39
|
+
def property_name(property)
|
40
|
+
property.is_a?(Hash) ? property.keys.first : property
|
61
41
|
end
|
62
42
|
|
63
|
-
|
64
|
-
|
65
|
-
type:
|
66
|
-
|
43
|
+
def ref_descriptor(names)
|
44
|
+
{
|
45
|
+
type: :reference,
|
46
|
+
anyOf: names.map { |name| { :$ref => "#/components/schemas/#{name.singularize}" } }
|
67
47
|
}
|
68
48
|
end
|
69
49
|
|
70
|
-
|
71
|
-
|
50
|
+
def property_type_and_format_attr(name) # rubocop:todo Metrics/MethodLength
|
51
|
+
atype = attribute_types[name.to_s].type
|
72
52
|
|
73
|
-
|
74
|
-
|
53
|
+
# The PG array delegates type to "subtype" which is the actual type of the array elements
|
54
|
+
if attribute_types[name.to_s].is_a? ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array
|
55
|
+
return {
|
56
|
+
type: :array,
|
57
|
+
items: {
|
58
|
+
type: atype
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
75
62
|
|
76
|
-
|
63
|
+
if %i[datetime date time].include?(atype)
|
64
|
+
return {
|
65
|
+
type: "string",
|
66
|
+
format: atype
|
67
|
+
}
|
68
|
+
end
|
77
69
|
|
78
|
-
|
79
|
-
array_options[:creatable] = true
|
80
|
-
array_options[:updatable] = true
|
81
|
-
array_options[:destroyable] = nested_attributes_options[ref_sym][:allow_destroy]
|
70
|
+
{ type: atype }
|
82
71
|
end
|
83
72
|
|
84
|
-
|
85
|
-
|
73
|
+
def nested_array_options(name)
|
74
|
+
ref_sym = name.to_sym
|
86
75
|
|
87
|
-
|
88
|
-
# rubocop:todo Metrics/AbcSize
|
89
|
-
def property_type_and_format_ref(name) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
|
90
|
-
assoc = reflections[name]
|
91
|
-
klasses = if assoc.options[:polymorphic]
|
92
|
-
assoc.active_record.send("#{assoc.name}_types").map(&:constantize).map { |m| m.model_name.singular }
|
93
|
-
else
|
94
|
-
# FIXME: The tr hack is to match how model_name in rails handles modularized classes
|
95
|
-
[assoc.options[:class_name]&.underscore&.tr('/', '_') || name]
|
96
|
-
end
|
76
|
+
array_options = {}
|
97
77
|
|
98
|
-
|
78
|
+
if nested_attributes_options[ref_sym]
|
79
|
+
array_options[:creatable] = true
|
80
|
+
array_options[:updatable] = true
|
81
|
+
array_options[:destroyable] = nested_attributes_options[ref_sym][:allow_destroy]
|
82
|
+
end
|
99
83
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
84
|
+
{ "x-rhino-attribute-array": array_options.merge(_properties_array[ref_sym] || {}) }
|
85
|
+
end
|
86
|
+
|
87
|
+
# rubocop:todo Metrics/PerceivedComplexity
|
88
|
+
# rubocop:todo Metrics/AbcSize
|
89
|
+
def property_type_and_format_ref(name) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
|
90
|
+
assoc = reflections[name]
|
91
|
+
klasses = if assoc.options[:polymorphic]
|
92
|
+
# If its a delgated type it will have type introspection
|
93
|
+
if assoc.active_record.respond_to?("#{assoc.name}_types")
|
94
|
+
assoc.active_record.send("#{assoc.name}_types").map(&:constantize).map { |m| m.model_name.singular }
|
95
|
+
else
|
96
|
+
# FIXME: This is wrong, but there is no good way to introspect general polymorphic models
|
97
|
+
[name]
|
98
|
+
end
|
99
|
+
else
|
100
|
+
# FIXME: The tr hack is to match how model_name in rails handles modularized classes
|
101
|
+
[assoc.options[:class_name]&.underscore&.tr("/", "_") || name]
|
102
|
+
end
|
107
103
|
|
108
|
-
|
109
|
-
# Special cases
|
110
|
-
return { type: :identifier } if name == identifier_property
|
111
|
-
return { type: :string } if defined_enums.key?(name)
|
104
|
+
return ref_descriptor(klasses) unless reflections[name].macro == :has_many
|
112
105
|
|
113
|
-
|
114
|
-
if attribute_types.key?(name.to_s) && attribute_types[name.to_s].class.to_s == 'ActsAsTaggableOn::Taggable::TagListType'
|
115
|
-
return {
|
106
|
+
{
|
116
107
|
type: :array,
|
117
|
-
items:
|
118
|
-
type: 'string'
|
119
|
-
}
|
108
|
+
items: ref_descriptor(klasses).merge(nested_array_options(name))
|
120
109
|
}
|
121
110
|
end
|
111
|
+
# rubocop:enable Metrics/AbcSize
|
112
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
113
|
+
|
114
|
+
def property_type_and_format(name) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
115
|
+
# Special cases
|
116
|
+
return { type: :identifier } if name == identifier_property
|
117
|
+
return { type: :string } if defined_enums.key?(name)
|
118
|
+
|
119
|
+
# FIXME: Hack for tags for now
|
120
|
+
if attribute_types.key?(name.to_s) && attribute_types[name.to_s].class.to_s == "ActsAsTaggableOn::Taggable::TagListType"
|
121
|
+
return {
|
122
|
+
type: :array,
|
123
|
+
items: {
|
124
|
+
type: "string"
|
125
|
+
}
|
126
|
+
}
|
127
|
+
end
|
122
128
|
|
123
|
-
|
124
|
-
|
129
|
+
# Use the attribute type if possible
|
130
|
+
return property_type_and_format_attr(name) if attribute_types.key?(name.to_s)
|
125
131
|
|
126
|
-
|
132
|
+
return property_type_and_format_ref(name) if reflections.key?(name)
|
127
133
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
134
|
+
# FIXME: There may be no way to reach this
|
135
|
+
# raise UnknownpropertyType
|
136
|
+
{ type: :unknown }
|
137
|
+
end
|
132
138
|
|
133
|
-
|
134
|
-
|
139
|
+
def property_overrides(property)
|
140
|
+
return {} unless _properties_overrides.key?(property)
|
135
141
|
|
136
|
-
|
137
|
-
|
142
|
+
_properties_overrides[property].deep_symbolize_keys
|
143
|
+
end
|
138
144
|
|
139
|
-
|
140
|
-
|
145
|
+
def property_validations(property) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
146
|
+
constraint_hash = {}
|
141
147
|
|
142
|
-
|
148
|
+
# https://swagger.io/specification/
|
143
149
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
+
validators_on(property).each do |v|
|
151
|
+
if v.is_a? ActiveModel::Validations::NumericalityValidator
|
152
|
+
if v.options.key?(:greater_than)
|
153
|
+
constraint_hash[:minimum] = v.options[:greater_than]
|
154
|
+
constraint_hash[:exclusiveMinimum] = true
|
155
|
+
end
|
150
156
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
157
|
+
if v.options.key?(:less_than)
|
158
|
+
constraint_hash[:maximum] = v.options[:less_than]
|
159
|
+
constraint_hash[:exclusiveMaximum] = true
|
160
|
+
end
|
155
161
|
|
156
|
-
|
157
|
-
|
162
|
+
constraint_hash[:minimum] = v.options[:greater_than_or_equal_to] if v.options.key?(:greater_than_or_equal_to)
|
163
|
+
constraint_hash[:maximum] = v.options[:less_than_or_equal_to] if v.options.key?(:less_than_or_equal_to)
|
158
164
|
|
159
|
-
|
160
|
-
|
161
|
-
|
165
|
+
if v.options.key?(:in)
|
166
|
+
constraint_hash[:minimum] = v.options[:in].min
|
167
|
+
constraint_hash[:maximum] = v.options[:in].max
|
168
|
+
end
|
162
169
|
end
|
163
|
-
end
|
164
|
-
|
165
|
-
if v.is_a? ::ActiveRecord::Validations::LengthValidator
|
166
|
-
constraint_hash[:minLength] = v.options[:minimum] || v.options[:is]
|
167
|
-
constraint_hash[:maxLength] = v.options[:maximum] || v.options[:is]
|
168
|
-
end
|
169
170
|
|
170
|
-
|
171
|
+
if v.is_a? ::ActiveRecord::Validations::LengthValidator
|
172
|
+
constraint_hash[:minLength] = v.options[:minimum] || v.options[:is]
|
173
|
+
constraint_hash[:maxLength] = v.options[:maximum] || v.options[:is]
|
174
|
+
end
|
171
175
|
|
172
|
-
|
173
|
-
end
|
176
|
+
constraint_hash[:pattern] = JsRegex.new(v.options[:with]).source if v.is_a? ::ActiveModel::Validations::FormatValidator
|
174
177
|
|
175
|
-
|
178
|
+
constraint_hash[:enum] = v.options[:in] if v.is_a? ActiveModel::Validations::InclusionValidator
|
179
|
+
end
|
176
180
|
|
177
|
-
|
178
|
-
end
|
181
|
+
constraint_hash[:enum] = defined_enums[property].keys if defined_enums.key?(property)
|
179
182
|
|
180
|
-
|
181
|
-
# if there is no optional: true on an association, rails will add a
|
182
|
-
# presence validator automatically
|
183
|
-
# Otherwise check the db for the actual column or foreign key setting
|
184
|
-
# Return nil instead of false for compaction
|
185
|
-
def property_nullable?(name) # rubocop:todo Metrics/AbcSize
|
186
|
-
# Check for any presence validator
|
187
|
-
return false if validators_on(name).any?(::ActiveRecord::Validations::PresenceValidator)
|
188
|
-
|
189
|
-
# https://guides.rubyonrails.org/active_record_validations.html#numericality
|
190
|
-
# By default, numericality doesn't allow nil values. You can use allow_nil: true option to permit it.
|
191
|
-
validators_on(name).select { |v| v.is_a? ::ActiveRecord::Validations::NumericalityValidator }.each do |v|
|
192
|
-
return false unless v.options[:allow_nil]
|
183
|
+
constraint_hash.compact
|
193
184
|
end
|
194
185
|
|
195
|
-
|
186
|
+
# If there is a presence validator in the model it is not nullable.
|
187
|
+
# if there is no optional: true on an association, rails will add a
|
188
|
+
# presence validator automatically
|
189
|
+
# Otherwise check the db for the actual column or foreign key setting
|
190
|
+
# Return nil instead of false for compaction
|
191
|
+
def property_nullable?(name) # rubocop:todo Metrics/AbcSize
|
192
|
+
# Check for any presence validator
|
193
|
+
return false if validators_on(name).any?(::ActiveRecord::Validations::PresenceValidator)
|
194
|
+
|
195
|
+
# https://guides.rubyonrails.org/active_record_validations.html#numericality
|
196
|
+
# By default, numericality doesn't allow nil values. You can use allow_nil: true option to permit it.
|
197
|
+
validators_on(name).select { |v| v.is_a? ::ActiveRecord::Validations::NumericalityValidator }.each do |v|
|
198
|
+
return false unless v.options[:allow_nil]
|
199
|
+
end
|
196
200
|
|
197
|
-
|
198
|
-
return columns_hash[name].null if columns_hash.key?(name)
|
201
|
+
name = reflections[name].foreign_key if reflections.key?(name)
|
199
202
|
|
200
|
-
|
201
|
-
|
203
|
+
# Check the column null setting
|
204
|
+
return columns_hash[name].null if columns_hash.key?(name)
|
202
205
|
|
203
|
-
|
204
|
-
|
205
|
-
return unless read_properties.include?(name) && (create_properties.exclude?(name) && update_properties.exclude?(name))
|
206
|
+
true
|
207
|
+
end
|
206
208
|
|
207
|
-
|
208
|
-
|
209
|
+
# Return nil instead of false for compaction
|
210
|
+
def property_read_only?(name)
|
211
|
+
return unless read_properties.include?(name) && (create_properties.exclude?(name) && update_properties.exclude?(name))
|
209
212
|
|
210
|
-
|
211
|
-
|
212
|
-
return unless (create_properties.include?(name) || update_properties.include?(name)) && read_properties.exclude?(name)
|
213
|
+
true
|
214
|
+
end
|
213
215
|
|
214
|
-
|
215
|
-
|
216
|
+
# Return nil instead of false for compaction
|
217
|
+
def property_write_only?(name)
|
218
|
+
return unless (create_properties.include?(name) || update_properties.include?(name)) && read_properties.exclude?(name)
|
216
219
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
220
|
+
true
|
221
|
+
end
|
222
|
+
|
223
|
+
def property_default(name)
|
224
|
+
# FIXME: This will not handle datetime fields
|
225
|
+
# https://github.com/rails/rails/issues/27077 sets the default in the db
|
226
|
+
# but Blog.new does not set the default value like other attributes
|
227
|
+
# https://nubinary.atlassian.net/browse/NUB-298
|
228
|
+
_default_attributes[name].type_cast(_default_attributes[name].value_before_type_cast)
|
229
|
+
end
|
224
230
|
end
|
225
231
|
end
|
226
232
|
end
|
data/lib/rhino/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rhino_project_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.21.0.beta.
|
4
|
+
version: 0.21.0.beta.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- JP Rosevear
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|