torque-postgresql 0.2.16 → 1.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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.rdoc +76 -3
  3. data/lib/torque-postgresql.rb +1 -0
  4. data/lib/torque/postgresql.rb +6 -0
  5. data/lib/torque/postgresql/adapter.rb +2 -4
  6. data/lib/torque/postgresql/adapter/database_statements.rb +23 -9
  7. data/lib/torque/postgresql/adapter/oid.rb +12 -1
  8. data/lib/torque/postgresql/adapter/oid/box.rb +28 -0
  9. data/lib/torque/postgresql/adapter/oid/circle.rb +37 -0
  10. data/lib/torque/postgresql/adapter/oid/enum.rb +9 -5
  11. data/lib/torque/postgresql/adapter/oid/enum_set.rb +44 -0
  12. data/lib/torque/postgresql/adapter/oid/line.rb +59 -0
  13. data/lib/torque/postgresql/adapter/oid/range.rb +52 -0
  14. data/lib/torque/postgresql/adapter/oid/segment.rb +73 -0
  15. data/lib/torque/postgresql/adapter/quoting.rb +21 -0
  16. data/lib/torque/postgresql/adapter/schema_definitions.rb +7 -0
  17. data/lib/torque/postgresql/adapter/schema_dumper.rb +10 -1
  18. data/lib/torque/postgresql/arel.rb +3 -0
  19. data/lib/torque/postgresql/arel/infix_operation.rb +42 -0
  20. data/lib/torque/postgresql/arel/nodes.rb +32 -0
  21. data/lib/torque/postgresql/arel/operations.rb +18 -0
  22. data/lib/torque/postgresql/arel/visitors.rb +28 -2
  23. data/lib/torque/postgresql/associations.rb +8 -0
  24. data/lib/torque/postgresql/associations/association.rb +30 -0
  25. data/lib/torque/postgresql/associations/association_scope.rb +116 -0
  26. data/lib/torque/postgresql/associations/belongs_to_many_association.rb +117 -0
  27. data/lib/torque/postgresql/associations/builder.rb +2 -0
  28. data/lib/torque/postgresql/associations/builder/belongs_to_many.rb +121 -0
  29. data/lib/torque/postgresql/associations/builder/has_many.rb +15 -0
  30. data/lib/torque/postgresql/associations/join_dependency/join_association.rb +15 -0
  31. data/lib/torque/postgresql/associations/preloader.rb +25 -0
  32. data/lib/torque/postgresql/associations/preloader/association.rb +64 -0
  33. data/lib/torque/postgresql/attributes.rb +2 -0
  34. data/lib/torque/postgresql/attributes/builder.rb +1 -0
  35. data/lib/torque/postgresql/attributes/builder/enum.rb +23 -15
  36. data/lib/torque/postgresql/attributes/builder/period.rb +452 -0
  37. data/lib/torque/postgresql/attributes/enum.rb +11 -8
  38. data/lib/torque/postgresql/attributes/enum_set.rb +256 -0
  39. data/lib/torque/postgresql/attributes/lazy.rb +1 -1
  40. data/lib/torque/postgresql/attributes/period.rb +31 -0
  41. data/lib/torque/postgresql/attributes/type_map.rb +3 -5
  42. data/lib/torque/postgresql/autosave_association.rb +40 -0
  43. data/lib/torque/postgresql/auxiliary_statement.rb +201 -198
  44. data/lib/torque/postgresql/auxiliary_statement/settings.rb +20 -12
  45. data/lib/torque/postgresql/base.rb +161 -2
  46. data/lib/torque/postgresql/config.rb +91 -9
  47. data/lib/torque/postgresql/geometry_builder.rb +92 -0
  48. data/lib/torque/postgresql/i18n.rb +1 -1
  49. data/lib/torque/postgresql/railtie.rb +18 -5
  50. data/lib/torque/postgresql/reflection.rb +21 -0
  51. data/lib/torque/postgresql/reflection/abstract_reflection.rb +109 -0
  52. data/lib/torque/postgresql/reflection/association_reflection.rb +30 -0
  53. data/lib/torque/postgresql/reflection/belongs_to_many_reflection.rb +44 -0
  54. data/lib/torque/postgresql/reflection/has_many_reflection.rb +13 -0
  55. data/lib/torque/postgresql/reflection/runtime_reflection.rb +12 -0
  56. data/lib/torque/postgresql/reflection/through_reflection.rb +11 -0
  57. data/lib/torque/postgresql/relation.rb +11 -10
  58. data/lib/torque/postgresql/relation/auxiliary_statement.rb +11 -18
  59. data/lib/torque/postgresql/relation/inheritance.rb +2 -2
  60. data/lib/torque/postgresql/relation/merger.rb +11 -7
  61. data/lib/torque/postgresql/schema_cache.rb +1 -1
  62. data/lib/torque/postgresql/version.rb +1 -1
  63. data/lib/torque/range.rb +40 -0
  64. metadata +41 -9
@@ -0,0 +1,452 @@
1
+ module Torque
2
+ module PostgreSQL
3
+ module Attributes
4
+ module Builder
5
+ # TODO: Allow methods to have nil in order to not include that specific method
6
+ class Period
7
+ SUPPORTED_TYPES = %i[daterange tsrange tstzrange].freeze
8
+ CURRENT_GETTERS = {
9
+ daterange: 'Date.today',
10
+ tsrange: 'Time.zone.now',
11
+ tstzrange: 'Time.zone.now',
12
+ }.freeze
13
+
14
+ TYPE_CASTERS = {
15
+ daterange: :date,
16
+ tsrange: :timestamp,
17
+ tstzrange: :timestamp,
18
+ }.freeze
19
+
20
+ attr_accessor :klass, :attribute, :options, :type, :arel_attribute, :default,
21
+ :current_getter, :type_caster, :default_sql, :threshold, :dynamic_threshold,
22
+ :period_module
23
+
24
+ # Start a new builder of methods for period values on
25
+ # ActiveRecord::Base
26
+ def initialize(klass, attribute, _, options)
27
+ @klass = klass
28
+ @attribute = attribute.to_s
29
+ @options = options
30
+ @type = klass.attribute_types[@attribute].type
31
+
32
+ @arel_attribute = klass.arel_table[@attribute]
33
+ @current_getter = CURRENT_GETTERS[type]
34
+ @type_caster = TYPE_CASTERS[type]
35
+
36
+ @default = options[:pessimistic].blank?
37
+ @default_sql = ::Arel.sql(klass.connection.quote(@default))
38
+
39
+ @threshold = options[:threshold].presence
40
+
41
+ raise ArgumentError, <<-MSG.squish unless SUPPORTED_TYPES.include?(type)
42
+ Period cannot be generated for #{attribute} because its type
43
+ #{type} is not supported. Only #{SUPPORTED_TYPES.join(', ')} are supported.
44
+ MSG
45
+ end
46
+
47
+ # Generate all the method names
48
+ def method_names
49
+ @method_names ||= options.fetch(:methods, {}).symbolize_keys
50
+ .reverse_merge(default_method_names)
51
+ end
52
+
53
+ # Get the list of methods associated withe the class
54
+ def klass_method_names
55
+ @klass_method_names ||= method_names.to_a[0..20].to_h
56
+ end
57
+
58
+ # Get the list of methods associated withe the instances
59
+ def instance_method_names
60
+ @instance_method_names ||= method_names.to_a[21..27].to_h
61
+ end
62
+
63
+ # Check if any of the methods that will be created get in conflict
64
+ # with the base class methods
65
+ def conflicting?
66
+ return false if options[:force] == true
67
+
68
+ klass_method_names.values.each { |name| dangerous?(name, true) }
69
+ instance_method_names.values.each { |name| dangerous?(name) }
70
+
71
+ return false
72
+ rescue Interrupt => err
73
+ raise ArgumentError, <<-MSG.squish
74
+ #{subtype.class.name} was not able to generate requested
75
+ methods because the method #{err} already exists in
76
+ #{klass.name}.
77
+ MSG
78
+ end
79
+
80
+ # Create all methods needed
81
+ def build
82
+ @period_module = Module.new
83
+
84
+ build_singleton_methods
85
+ build_instance_methods
86
+
87
+ klass.include period_module
88
+ end
89
+
90
+ # When the time has a threshold, then the real attribute is complex
91
+ def real_arel_attribute
92
+ return arel_attribute unless threshold.present?
93
+
94
+ left = named_function(:lower, arel_attribute) - threshold_value
95
+ right = named_function(:upper, arel_attribute) + threshold_value
96
+
97
+ if type.eql?(:daterange)
98
+ left = left.cast(:date)
99
+ right = right.cast(:date)
100
+ end
101
+
102
+ @real_arel_attribute ||= named_function(type, left, right)
103
+ end
104
+
105
+ # Create an arel named function
106
+ def named_function(name, *args)
107
+ ::Arel::Nodes::NamedFunction.new(name.to_s, args)
108
+ end
109
+
110
+ # Create an arel version of +nullif+ function
111
+ def arel_nullif(*args)
112
+ named_function('nullif', args)
113
+ end
114
+
115
+ # Create an arel version of +coalesce+ function
116
+ def arel_coalesce(*args)
117
+ named_function('coalesce', args)
118
+ end
119
+
120
+ # Create an arel version of the type with the following values
121
+ def arel_convert_to_type(left, right = nil, set_type = nil)
122
+ named_function(set_type || type, [left, right || left])
123
+ end
124
+
125
+ # Convert timestamp range to date range format
126
+ def arel_daterange
127
+ named_function(
128
+ :daterange,
129
+ named_function(:lower, real_arel_attribute).cast(:date),
130
+ named_function(:upper, real_arel_attribute).cast(:date),
131
+ )
132
+ end
133
+
134
+ # Create an arel version of an empty value for the range
135
+ def arel_empty_value
136
+ arel_convert_to_type(::Arel.sql('NULL'))
137
+ end
138
+
139
+ # Create an arel not condition
140
+ def arel_not(value)
141
+ named_function(:not, value)
142
+ end
143
+
144
+ # Get the main arel condition to check the value
145
+ def arel_check_condition(type, value)
146
+ value = ::Arel.sql(klass.connection.quote(value))
147
+
148
+ checker = arel_nullif(real_arel_attribute, arel_empty_value)
149
+ checker = checker.public_send(type, value.cast(type_caster))
150
+ arel_coalesce(checker, default_sql)
151
+ end
152
+
153
+ # Check how to provide the threshold value
154
+ def threshold_value
155
+ @threshold_value ||= begin
156
+ case threshold
157
+ when Symbol, String
158
+ klass.arel_table[threshold]
159
+ when ActiveSupport::Duration
160
+ ::Arel.sql("'#{threshold.to_i} seconds'").cast(:interval)
161
+ when Numeric
162
+ value = threshold.to_i.to_s
163
+ value << type_caster.eql?(:date) ? ' days' : ' seconds'
164
+ ::Arel.sql("'#{value}'").cast(:interval)
165
+ end
166
+ end
167
+ end
168
+
169
+ private
170
+
171
+ # Generates the default method names
172
+ def default_method_names
173
+ Torque::PostgreSQL.config.period.method_names.transform_values do |value|
174
+ format(value, attribute)
175
+ end
176
+ end
177
+
178
+ # Check if the method already exists in the reference class
179
+ def dangerous?(method_name, class_method = false)
180
+ if class_method
181
+ if klass.dangerous_class_method?(method_name)
182
+ raise Interrupt, method_name.to_s
183
+ end
184
+ else
185
+ if klass.dangerous_attribute_method?(method_name)
186
+ raise Interrupt, method_name.to_s
187
+ end
188
+ end
189
+ end
190
+
191
+ # Build model methods
192
+ def build_singleton_methods
193
+ attr = attribute
194
+ builder = self
195
+
196
+ # TODO: Rewrite these as string
197
+ klass.scope method_names[:current_on], ->(value) do
198
+ where(builder.arel_check_condition(:contains, value))
199
+ end
200
+
201
+ klass.scope method_names[:current], -> do
202
+ public_send(builder.method_names[:current_on], eval(builder.current_getter))
203
+ end
204
+
205
+ klass.scope method_names[:not_current], -> do
206
+ current_value = eval(builder.current_getter)
207
+ where.not(builder.arel_check_condition(:contains, current_value))
208
+ end
209
+
210
+ klass.scope method_names[:containing], ->(value) do
211
+ value = arel_table[value] if value.is_a?(Symbol)
212
+ value = ::Arel.sql(connection.quote(value)) unless value.respond_to?(:cast)
213
+ where(builder.arel_attribute.contains(value))
214
+ end
215
+
216
+ klass.scope method_names[:not_containing], ->(value) do
217
+ value = arel_table[value] if value.is_a?(Symbol)
218
+ value = ::Arel.sql(connection.quote(value)) unless value.respond_to?(:cast)
219
+ where.not(builder.arel_attribute.contains(value))
220
+ end
221
+
222
+ klass.scope method_names[:overlapping], ->(value, right = nil) do
223
+ value = arel_table[value] if value.is_a?(Symbol)
224
+
225
+ if right.present?
226
+ value = ::Arel.sql(connection.quote(value))
227
+ right = ::Arel.sql(connection.quote(right))
228
+ value = builder.arel_convert_to_type(value, right)
229
+ elsif !value.respond_to?(:cast)
230
+ value = ::Arel.sql(connection.quote(value))
231
+ end
232
+
233
+ where(builder.arel_attribute.overlaps(value))
234
+ end
235
+
236
+ klass.scope method_names[:not_overlapping], ->(value, right = nil) do
237
+ value = arel_table[value] if value.is_a?(Symbol)
238
+
239
+ if right.present?
240
+ value = ::Arel.sql(connection.quote(value))
241
+ right = ::Arel.sql(connection.quote(right))
242
+ value = builder.arel_convert_to_type(value, right)
243
+ elsif !value.respond_to?(:cast)
244
+ value = ::Arel.sql(connection.quote(value))
245
+ end
246
+
247
+ where.not(builder.arel_attribute.overlaps(value))
248
+ end
249
+
250
+ klass.scope method_names[:starting_after], ->(value) do
251
+ value = arel_table[value] if value.is_a?(Symbol)
252
+ value = ::Arel.sql(connection.quote(value)) \
253
+ unless value.is_a?(::Arel::Attributes::Attribute)
254
+
255
+ where(builder.named_function(:lower, builder.arel_attribute).gt(value))
256
+ end
257
+
258
+ klass.scope method_names[:starting_before], ->(value) do
259
+ value = arel_table[value] if value.is_a?(Symbol)
260
+ value = ::Arel.sql(connection.quote(value)) \
261
+ unless value.is_a?(::Arel::Attributes::Attribute)
262
+
263
+ where(builder.named_function(:lower, builder.arel_attribute).lt(value))
264
+ end
265
+
266
+ klass.scope method_names[:finishing_after], ->(value) do
267
+ value = arel_table[value] if value.is_a?(Symbol)
268
+ value = ::Arel.sql(connection.quote(value)) \
269
+ unless value.is_a?(::Arel::Attributes::Attribute)
270
+
271
+ where(builder.named_function(:upper, builder.arel_attribute).gt(value))
272
+ end
273
+
274
+ klass.scope method_names[:finishing_before], ->(value) do
275
+ value = arel_table[value] if value.is_a?(Symbol)
276
+ value = ::Arel.sql(connection.quote(value)) \
277
+ unless value.is_a?(::Arel::Attributes::Attribute)
278
+
279
+ where(builder.named_function(:upper, builder.arel_attribute).lt(value))
280
+ end
281
+
282
+ if threshold.present?
283
+ klass.scope method_names[:real_containing], ->(value) do
284
+ value = arel_table[value] if value.is_a?(Symbol)
285
+ value = ::Arel.sql(connection.quote(value)) unless value.respond_to?(:cast)
286
+ where(builder.real_arel_attribute.contains(value))
287
+ end
288
+
289
+ klass.scope method_names[:real_overlapping], ->(value, right = nil) do
290
+ value = arel_table[value] if value.is_a?(Symbol)
291
+
292
+ if right.present?
293
+ value = ::Arel.sql(connection.quote(value))
294
+ right = ::Arel.sql(connection.quote(right))
295
+ value = builder.arel_convert_to_type(value, right)
296
+ elsif !value.respond_to?(:cast)
297
+ value = ::Arel.sql(connection.quote(value))
298
+ end
299
+
300
+ where(builder.real_arel_attribute.overlaps(value))
301
+ end
302
+
303
+ klass.scope method_names[:real_starting_after], ->(value) do
304
+ value = arel_table[value] if value.is_a?(Symbol)
305
+ condition = builder.named_function(:lower, builder.arel_attribute)
306
+ condition -= builder.threshold_value
307
+ condition = condition.cast(:date) if builder.type.eql?(:daterange)
308
+ where(condition.gt(value))
309
+ end
310
+
311
+ klass.scope method_names[:real_starting_before], ->(value) do
312
+ value = arel_table[value] if value.is_a?(Symbol)
313
+ condition = builder.named_function(:lower, builder.arel_attribute)
314
+ condition -= builder.threshold_value
315
+ condition = condition.cast(:date) if builder.type.eql?(:daterange)
316
+ where(condition.lt(value))
317
+ end
318
+
319
+ klass.scope method_names[:real_finishing_after], ->(value) do
320
+ value = arel_table[value] if value.is_a?(Symbol)
321
+ condition = builder.named_function(:upper, builder.arel_attribute)
322
+ condition += builder.threshold_value
323
+ condition = condition.cast(:date) if builder.type.eql?(:daterange)
324
+ where(condition.gt(value))
325
+ end
326
+
327
+ klass.scope method_names[:real_finishing_before], ->(value) do
328
+ value = arel_table[value] if value.is_a?(Symbol)
329
+ condition = builder.named_function(:upper, builder.arel_attribute)
330
+ condition += builder.threshold_value
331
+ condition = condition.cast(:date) if builder.type.eql?(:daterange)
332
+ where(condition.lt(value))
333
+ end
334
+ end
335
+
336
+ unless type.eql?(:daterange)
337
+ klass.scope method_names[:containing_date], ->(value) do
338
+ value = arel_table[value] if value.is_a?(Symbol)
339
+ value = ::Arel.sql(connection.quote(value)) unless value.respond_to?(:cast)
340
+ where(builder.arel_daterange.contains(value))
341
+ end
342
+
343
+ klass.scope method_names[:not_containing_date], ->(value) do
344
+ value = arel_table[value] if value.is_a?(Symbol)
345
+ value = ::Arel.sql(connection.quote(value)) unless value.respond_to?(:cast)
346
+ where.not(builder.arel_daterange.contains(value))
347
+ end
348
+
349
+ klass.scope method_names[:overlapping_date], ->(value, right = nil) do
350
+ value = arel_table[value] if value.is_a?(Symbol)
351
+
352
+ if right.present?
353
+ value = ::Arel.sql(connection.quote(value))
354
+ right = ::Arel.sql(connection.quote(right))
355
+ value = builder.arel_convert_to_type(value, right, :daterange)
356
+ elsif !value.respond_to?(:cast)
357
+ value = ::Arel.sql(connection.quote(value))
358
+ end
359
+
360
+ where(builder.arel_daterange.overlaps(value))
361
+ end
362
+
363
+ klass.scope method_names[:not_overlapping_date], ->(value, right = nil) do
364
+ value = arel_table[value] if value.is_a?(Symbol)
365
+
366
+ if right.present?
367
+ value = ::Arel.sql(connection.quote(value))
368
+ right = ::Arel.sql(connection.quote(right))
369
+ value = builder.arel_convert_to_type(value, right, :daterange)
370
+ elsif !value.respond_to?(:cast)
371
+ value = ::Arel.sql(connection.quote(value))
372
+ end
373
+
374
+ where.not(builder.arel_daterange.overlaps(value))
375
+ end
376
+ end
377
+ end
378
+
379
+ # Build model instance methods
380
+ def build_instance_methods
381
+ attr = attribute
382
+ builder = self
383
+
384
+ attr_threshold = threshold
385
+ attr_threshold = attr_threshold.to_sym if attr_threshold.is_a?(String)
386
+ attr_threshold = attr_threshold.seconds if attr_threshold.is_a?(Numeric)
387
+
388
+ # TODO: Rewrite these as string
389
+ period_module.module_eval do
390
+ define_method(builder.method_names[:current?]) do
391
+ public_send(builder.method_names[:current_on?], eval(builder.current_getter))
392
+ end
393
+
394
+ define_method(builder.method_names[:current_on?]) do |value|
395
+ attr_value = builder.threshold ? builder.method_names[:real] : attr
396
+ attr_value = public_send(attr_value)
397
+
398
+ return builder.default if attr_value.nil? ||
399
+ (attr_value.min.try(:infinite?) && attr_value.max.try(:infinite?))
400
+
401
+ attr_value.min < value && attr_value.max > value
402
+ end
403
+
404
+ define_method(builder.method_names[:start]) do
405
+ public_send(attr)&.min
406
+ end
407
+
408
+ define_method(builder.method_names[:finish]) do
409
+ public_send(attr)&.max
410
+ end
411
+
412
+ if attr_threshold.present?
413
+ define_method(builder.method_names[:start]) do
414
+ public_send(attr)&.min
415
+ end
416
+
417
+ define_method(builder.method_names[:finish]) do
418
+ public_send(attr)&.max
419
+ end
420
+
421
+ define_method(builder.method_names[:real]) do
422
+ left = public_send(builder.method_names[:real_start])
423
+ right = public_send(builder.method_names[:real_finish])
424
+ return unless left || right
425
+
426
+ left ||= -::Float::INFINITY
427
+ right ||= ::Float::INFINITY
428
+
429
+ (left..right)
430
+ end
431
+
432
+ define_method(builder.method_names[:real_start]) do
433
+ threshold = attr_threshold
434
+ threshold = public_send(threshold) if threshold.is_a?(Symbol)
435
+ result = public_send(attr)&.min.try(:-, threshold)
436
+ builder.type.eql?(:daterange) ? result&.to_date : result
437
+ end
438
+
439
+ define_method(builder.method_names[:real_finish]) do
440
+ threshold = attr_threshold
441
+ threshold = public_send(threshold) if threshold.is_a?(Symbol)
442
+ result = public_send(attr)&.max.try(:+, threshold)
443
+ builder.type.eql?(:daterange) ? result&.to_date : result
444
+ end
445
+ end
446
+ end
447
+ end
448
+ end
449
+ end
450
+ end
451
+ end
452
+ end
@@ -11,7 +11,7 @@ module Torque
11
11
  class << self
12
12
  include Enumerable
13
13
 
14
- delegate :each, :sample, to: :members
14
+ delegate :each, :sample, :size, :length, to: :members
15
15
 
16
16
  # Find or create the class that will handle the value
17
17
  def lookup(name)
@@ -72,8 +72,7 @@ module Torque
72
72
  # see https://github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/fixtures.rb#L656
73
73
  # see https://github.com/rails/rails/blob/v5.0.0/activerecord/lib/active_record/validations/uniqueness.rb#L101
74
74
  def fetch(value, *)
75
- return nil unless values.include?(value)
76
- send(value)
75
+ new(value.to_s) if values.include?(value)
77
76
  end
78
77
  alias [] fetch
79
78
 
@@ -89,11 +88,16 @@ module Torque
89
88
  self.values.include?(value.to_s)
90
89
  end
91
90
 
91
+ # Build an active record scope for a given atribute agains a value
92
+ def scope(attribute, value)
93
+ attribute.eq(value)
94
+ end
95
+
92
96
  private
93
97
 
94
98
  # Allows checking value existance
95
99
  def respond_to_missing?(method_name, include_private = false)
96
- valid?(method_name)
100
+ valid?(method_name) || super
97
101
  end
98
102
 
99
103
  # Allow fast creation of values
@@ -165,7 +169,7 @@ module Torque
165
169
 
166
170
  # Change the inspection to show the enum name
167
171
  def inspect
168
- nil? ? 'nil' : "#<#{self.class.name} #{super}>"
172
+ nil? ? 'nil' : ":#{to_s}"
169
173
  end
170
174
 
171
175
  private
@@ -199,9 +203,9 @@ module Torque
199
203
  name = method_name.to_s
200
204
 
201
205
  if name.chomp!('?')
202
- self == name.tr('_', '-') || self == name
206
+ self == name
203
207
  elsif name.chomp!('!')
204
- replace(name)
208
+ replace(name) unless self == name
205
209
  else
206
210
  super
207
211
  end
@@ -220,7 +224,6 @@ module Torque
220
224
  def raise_comparison(other)
221
225
  raise EnumError, "Comparison of #{self.class.name} with #{self.inspect} failed"
222
226
  end
223
-
224
227
  end
225
228
 
226
229
  # Create the methods related to the attribute to handle the enum type