simple_master 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.
- checksums.yaml +7 -0
- data/lib/simple_master/active_record/belongs_to_master_polymorphic_reflection.rb +11 -0
- data/lib/simple_master/active_record/belongs_to_polymorphic_association.rb +17 -0
- data/lib/simple_master/active_record/belongs_to_polymorphic_builder.rb +21 -0
- data/lib/simple_master/active_record/extension.rb +183 -0
- data/lib/simple_master/active_record/preloader_association_extension.rb +11 -0
- data/lib/simple_master/active_record.rb +12 -0
- data/lib/simple_master/loader/dataset_loader.rb +20 -0
- data/lib/simple_master/loader/marshal_loader.rb +15 -0
- data/lib/simple_master/loader/query_loader.rb +63 -0
- data/lib/simple_master/loader.rb +55 -0
- data/lib/simple_master/master/association/belongs_to_association.rb +79 -0
- data/lib/simple_master/master/association/belongs_to_polymorphic_association.rb +79 -0
- data/lib/simple_master/master/association/has_many_association.rb +53 -0
- data/lib/simple_master/master/association/has_many_through_association.rb +64 -0
- data/lib/simple_master/master/association/has_one_association.rb +57 -0
- data/lib/simple_master/master/association.rb +50 -0
- data/lib/simple_master/master/column/bitmask_column.rb +74 -0
- data/lib/simple_master/master/column/boolean_column.rb +51 -0
- data/lib/simple_master/master/column/enum_column.rb +96 -0
- data/lib/simple_master/master/column/float_column.rb +21 -0
- data/lib/simple_master/master/column/id_column.rb +31 -0
- data/lib/simple_master/master/column/integer_column.rb +21 -0
- data/lib/simple_master/master/column/json_column.rb +27 -0
- data/lib/simple_master/master/column/polymorphic_type_column.rb +44 -0
- data/lib/simple_master/master/column/sti_type_column.rb +21 -0
- data/lib/simple_master/master/column/string_column.rb +17 -0
- data/lib/simple_master/master/column/symbol_column.rb +23 -0
- data/lib/simple_master/master/column/time_column.rb +38 -0
- data/lib/simple_master/master/column.rb +138 -0
- data/lib/simple_master/master/dsl.rb +239 -0
- data/lib/simple_master/master/editable.rb +155 -0
- data/lib/simple_master/master/filterable.rb +47 -0
- data/lib/simple_master/master/queryable.rb +75 -0
- data/lib/simple_master/master/storable.rb +20 -0
- data/lib/simple_master/master/validatable.rb +216 -0
- data/lib/simple_master/master.rb +417 -0
- data/lib/simple_master/schema.rb +49 -0
- data/lib/simple_master/storage/dataset.rb +172 -0
- data/lib/simple_master/storage/ondemand_table.rb +68 -0
- data/lib/simple_master/storage/table.rb +197 -0
- data/lib/simple_master/storage/test_table.rb +69 -0
- data/lib/simple_master/storage.rb +11 -0
- data/lib/simple_master/version.rb +5 -0
- data/lib/simple_master.rb +62 -0
- metadata +128 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Association
|
|
6
|
+
class HasManyThroughAssociation < self
|
|
7
|
+
def foreign_key
|
|
8
|
+
@foreign_key ||= (options[:foreign_key] || ActiveSupport::Inflector.foreign_key(defined_at.to_s)).to_sym
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def through
|
|
12
|
+
@through ||= options[:through]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def through_association
|
|
16
|
+
@through_association ||=
|
|
17
|
+
begin
|
|
18
|
+
through_association = defined_at.all_has_many_associations.find { |ass| ass.name == through }
|
|
19
|
+
|
|
20
|
+
if through_association.nil?
|
|
21
|
+
fail "Association '#{through}' not found in has_many_associations. Use 'delegate' instead."
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
through_association
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
delegate :target_class, to: :through_association
|
|
29
|
+
|
|
30
|
+
def source
|
|
31
|
+
@source ||= options[:source] || ActiveSupport::Inflector.singularize(name)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def primary_key
|
|
35
|
+
@primary_key ||= options[:primary_key] || :id
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def init(master_class)
|
|
39
|
+
# check
|
|
40
|
+
through_association
|
|
41
|
+
|
|
42
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
43
|
+
def #{name}
|
|
44
|
+
Array.wrap(#{through}).flat_map { |ass| ass.#{source} }.compact
|
|
45
|
+
end
|
|
46
|
+
RUBY
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def init_for_test(master_class)
|
|
50
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
51
|
+
def #{name}=(values)
|
|
52
|
+
self.#{through} = values.map { |value|
|
|
53
|
+
#{through_association.target_class}.new.tap do |through|
|
|
54
|
+
through.#{source} = value
|
|
55
|
+
#{"through.#{through_association.inverse_of} = self" if through_association.try(:inverse_of)}
|
|
56
|
+
end
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
RUBY
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Association
|
|
6
|
+
class HasOneAssociation < self
|
|
7
|
+
def foreign_key
|
|
8
|
+
@foreign_key ||= (options[:foreign_key] || ActiveSupport::Inflector.foreign_key(defined_at.to_s)).to_sym
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def inverse_of
|
|
12
|
+
@inverse_of ||= options[:inverse_of] || ActiveSupport::Inflector.underscore(defined_at.to_s)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def primary_key
|
|
16
|
+
@primary_key ||= options[:primary_key] || defined_at.primary_key || :id
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def init(master_class)
|
|
20
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
21
|
+
if #{target_class} < SimpleMaster::Master
|
|
22
|
+
def #{name}
|
|
23
|
+
#{target_class}.find_by(:#{foreign_key}, #{primary_key})
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
def #{name}
|
|
27
|
+
# Store in an Array so nil values still hit the cache
|
|
28
|
+
values = (has_many_store[:#{name}] ||= [#{target_class}.simple_master_connection.find_by_#{foreign_key}(#{primary_key})])
|
|
29
|
+
values.first
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
RUBY
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def init_for_test(master_class)
|
|
36
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
37
|
+
if #{target_class} < SimpleMaster::Master
|
|
38
|
+
def #{name}
|
|
39
|
+
(has_many_store[:#{name}] || #{target_class}.all_by(:#{foreign_key}, #{primary_key})).first
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
def #{name}
|
|
43
|
+
# Store in an Array so nil values still hit the cache
|
|
44
|
+
values = (has_many_store[:#{name}] ||= [#{target_class}.simple_master_connection.find_by_#{foreign_key}(#{primary_key})])
|
|
45
|
+
values.first
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def #{name}=(value)
|
|
50
|
+
has_many_store[:#{name}] = [value]
|
|
51
|
+
end
|
|
52
|
+
RUBY
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Association
|
|
6
|
+
autoload :BelongsToAssociation, "simple_master/master/association/belongs_to_association"
|
|
7
|
+
autoload :BelongsToPolymorphicAssociation, "simple_master/master/association/belongs_to_polymorphic_association"
|
|
8
|
+
autoload :HasManyAssociation, "simple_master/master/association/has_many_association"
|
|
9
|
+
autoload :HasManyThroughAssociation, "simple_master/master/association/has_many_through_association"
|
|
10
|
+
autoload :HasOneAssociation, "simple_master/master/association/has_one_association"
|
|
11
|
+
|
|
12
|
+
attr_reader :name
|
|
13
|
+
attr_reader :defined_at
|
|
14
|
+
attr_reader :options
|
|
15
|
+
|
|
16
|
+
def initialize(master_class, name, options)
|
|
17
|
+
@name = name
|
|
18
|
+
@defined_at = master_class
|
|
19
|
+
@options = options
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Execute after definition phase.
|
|
23
|
+
def target_class
|
|
24
|
+
@target_class ||= find_class(defined_at, options[:class_name] || ActiveSupport::Inflector.classify(name))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def is_active_record?
|
|
28
|
+
target_class < ::ActiveRecord::Base
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def init(master_class)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def init_for_test(master_class)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def find_class(current, class_name)
|
|
40
|
+
loop do
|
|
41
|
+
return current.const_get(class_name, false)
|
|
42
|
+
rescue NameError => e
|
|
43
|
+
raise e if current == current.module_parent
|
|
44
|
+
|
|
45
|
+
current = current.module_parent
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class BitmaskColumn < self
|
|
7
|
+
attr_reader :name
|
|
8
|
+
attr_reader :bitmask
|
|
9
|
+
attr_reader :const_name
|
|
10
|
+
|
|
11
|
+
def initialize(name, options)
|
|
12
|
+
@bitmask = options[:bitmask]
|
|
13
|
+
@const_name = "BITMASK_FOR_#{name.upcase}"
|
|
14
|
+
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def init(master_class, for_test = false)
|
|
19
|
+
super
|
|
20
|
+
|
|
21
|
+
master_class.simple_master_module.const_set(const_name, bitmask) unless master_class.const_defined?(const_name)
|
|
22
|
+
|
|
23
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
24
|
+
def #{name}
|
|
25
|
+
return EMPTY_ARRAY if @#{name}.nil?
|
|
26
|
+
#{const_name}.filter_map.with_index {
|
|
27
|
+
_1 if (1 << _2) & @#{name} != 0
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def #{name}_value
|
|
32
|
+
@#{name}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def #{name}_value=(value)
|
|
36
|
+
#{code_for_dirty_check if for_test}
|
|
37
|
+
@#{name} = value&.to_i
|
|
38
|
+
end
|
|
39
|
+
RUBY
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def code_for_conversion
|
|
45
|
+
<<-RUBY
|
|
46
|
+
value = cache_object(:#{name}, value) { |value|
|
|
47
|
+
value = [value] if value.is_a?(Symbol)
|
|
48
|
+
|
|
49
|
+
if value.is_a?(Array)
|
|
50
|
+
bits = 0
|
|
51
|
+
value.each do |day|
|
|
52
|
+
bits |= 1 << #{const_name}.index(day)
|
|
53
|
+
end
|
|
54
|
+
bits
|
|
55
|
+
else
|
|
56
|
+
value&.to_i
|
|
57
|
+
end
|
|
58
|
+
}
|
|
59
|
+
RUBY
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def code_for_sql_value
|
|
63
|
+
<<-RUBY
|
|
64
|
+
@#{name}
|
|
65
|
+
RUBY
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def globalize
|
|
69
|
+
fail NotImplementedError
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class BooleanColumn < self
|
|
7
|
+
def init(master_class, for_test = false)
|
|
8
|
+
super
|
|
9
|
+
|
|
10
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
11
|
+
def #{name}?
|
|
12
|
+
!!#{name}
|
|
13
|
+
end
|
|
14
|
+
RUBY
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def code_for_conversion
|
|
20
|
+
<<-RUBY
|
|
21
|
+
value = cache_object(:#{name}, value) { |value|
|
|
22
|
+
if value.is_a?(Integer)
|
|
23
|
+
value != 0
|
|
24
|
+
elsif value.is_a?(String)
|
|
25
|
+
value.downcase == "true" || value == "1"
|
|
26
|
+
elsif value.nil?
|
|
27
|
+
value
|
|
28
|
+
else
|
|
29
|
+
!!value
|
|
30
|
+
end
|
|
31
|
+
}
|
|
32
|
+
RUBY
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def code_for_sql_value
|
|
36
|
+
<<-RUBY
|
|
37
|
+
# Convert to 0/1 for systems that do not support true/false
|
|
38
|
+
case #{name}
|
|
39
|
+
when true
|
|
40
|
+
1
|
|
41
|
+
when false
|
|
42
|
+
0
|
|
43
|
+
else
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
RUBY
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class EnumColumn < self
|
|
7
|
+
attr_reader :name
|
|
8
|
+
attr_reader :enum
|
|
9
|
+
attr_reader :const_name
|
|
10
|
+
attr_reader :prefix
|
|
11
|
+
attr_reader :suffix
|
|
12
|
+
|
|
13
|
+
def initialize(name, options)
|
|
14
|
+
@enum = options[:enum]
|
|
15
|
+
@const_name = "ENUM_FOR_#{name.upcase}"
|
|
16
|
+
@prefix = "#{options[:prefix] == true ? name : options[:prefix]}_" if options[:prefix]
|
|
17
|
+
@suffix = "_#{options[:suffix] == true ? name : options[:suffix]}" if options[:suffix]
|
|
18
|
+
|
|
19
|
+
super
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def init(master_class, for_test = false)
|
|
23
|
+
super
|
|
24
|
+
|
|
25
|
+
master_class.simple_master_module.const_set(const_name, enum.freeze) unless master_class.const_defined?(const_name)
|
|
26
|
+
|
|
27
|
+
master_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
28
|
+
def self.#{name.to_s.pluralize}
|
|
29
|
+
#{const_name}
|
|
30
|
+
end
|
|
31
|
+
RUBY
|
|
32
|
+
|
|
33
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
34
|
+
def #{name}_to_enum(value)
|
|
35
|
+
case value
|
|
36
|
+
when Integer
|
|
37
|
+
return #{const_name}.key(value)
|
|
38
|
+
when String
|
|
39
|
+
sym = value.to_sym
|
|
40
|
+
return sym if #{const_name}.key?(sym)
|
|
41
|
+
|
|
42
|
+
int_val = Integer(value, exception: false)
|
|
43
|
+
if int_val
|
|
44
|
+
result = #{const_name}.key(int_val)
|
|
45
|
+
return result if result
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
fail "Unsupported type \#{value.inspect}."
|
|
49
|
+
when Symbol, NilClass
|
|
50
|
+
return value
|
|
51
|
+
else
|
|
52
|
+
fail "Unsupported type \#{value.inspect}."
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def #{name.to_s.pluralize}
|
|
57
|
+
#{const_name}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def #{name}_before_type_cast
|
|
61
|
+
#{const_name}[#{name}]
|
|
62
|
+
end
|
|
63
|
+
RUBY
|
|
64
|
+
|
|
65
|
+
enum.each_key do |enum_name|
|
|
66
|
+
# Skip generating helpers for names that start with a digit
|
|
67
|
+
next if enum_name.match?(/\A\d/) && prefix.nil?
|
|
68
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
69
|
+
def #{prefix}#{enum_name}#{suffix}?
|
|
70
|
+
#{name} == :#{enum_name}
|
|
71
|
+
end
|
|
72
|
+
RUBY
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def code_for_conversion
|
|
79
|
+
<<-RUBY
|
|
80
|
+
value = cache_object(:#{name}, value) { #{name}_to_enum(_1) }
|
|
81
|
+
RUBY
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def code_for_sql_value
|
|
85
|
+
<<-RUBY
|
|
86
|
+
#{name}_before_type_cast
|
|
87
|
+
RUBY
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def globalize
|
|
91
|
+
fail NotImplementedError
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class FloatColumn < self
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def code_for_conversion
|
|
10
|
+
<<-RUBY
|
|
11
|
+
if value.is_a?(String) && value.strip.empty?
|
|
12
|
+
value = nil
|
|
13
|
+
else
|
|
14
|
+
value = value&.to_f
|
|
15
|
+
end
|
|
16
|
+
RUBY
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class IdColumn < self
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def code_for_conversion
|
|
10
|
+
<<-RUBY
|
|
11
|
+
value = value&.to_i
|
|
12
|
+
RUBY
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def code_for_dirty_check
|
|
16
|
+
<<-RUBY
|
|
17
|
+
unless @#{name} == value
|
|
18
|
+
dirty!
|
|
19
|
+
# IDs require updating @id_hash when changed
|
|
20
|
+
self.class.id_hash.delete(@#{name}) if @#{name}
|
|
21
|
+
end
|
|
22
|
+
RUBY
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def globalize
|
|
26
|
+
fail NotImplementedError
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class IntegerColumn < self
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def code_for_conversion
|
|
10
|
+
<<-RUBY
|
|
11
|
+
if value.is_a?(String) && value.strip.empty?
|
|
12
|
+
value = nil
|
|
13
|
+
else
|
|
14
|
+
value = value&.to_i
|
|
15
|
+
end
|
|
16
|
+
RUBY
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class JsonColumn < self
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def code_for_conversion
|
|
10
|
+
<<-RUBY
|
|
11
|
+
value = cache_object(:#{name}, value) { |value|
|
|
12
|
+
value = JSON.parse(value, symbolize_names: #{!!options[:symbolize_names]}) if value.is_a?(String)
|
|
13
|
+
value
|
|
14
|
+
}
|
|
15
|
+
RUBY
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def code_for_sql_value
|
|
19
|
+
<<-RUBY
|
|
20
|
+
# Use JSON.generate because to_json adds unnecessary escaping
|
|
21
|
+
#{name}&.then { JSON.generate(_1) }
|
|
22
|
+
RUBY
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class PolymorphicTypeColumn < self
|
|
7
|
+
def init(master_class, for_test = false)
|
|
8
|
+
super
|
|
9
|
+
|
|
10
|
+
master_class.simple_master_module.attr_reader :"#{name}_class"
|
|
11
|
+
master_class.simple_master_module.attr_reader name
|
|
12
|
+
|
|
13
|
+
master_class.simple_master_module.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
14
|
+
def #{name}=(value)
|
|
15
|
+
#{code_for_conversion}
|
|
16
|
+
#{code_for_dirty_check if for_test}
|
|
17
|
+
@#{name} = value
|
|
18
|
+
@#{name}_class = value&.then { ActiveSupport::Inflector.constantize(_1) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def #{name}_class=(klass)
|
|
22
|
+
#{"dirty! unless @#{name}_class == klass" if for_test}
|
|
23
|
+
@#{name} = klass.to_s
|
|
24
|
+
@#{name}_class = klass
|
|
25
|
+
end
|
|
26
|
+
RUBY
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def code_for_conversion
|
|
32
|
+
<<-RUBY
|
|
33
|
+
value = nil if value == ""
|
|
34
|
+
value = cache_object(:#{name}, value) { _1&.to_s }
|
|
35
|
+
RUBY
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def globalize
|
|
39
|
+
fail NotImplementedError
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class StiTypeColumn < self
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def code_for_conversion
|
|
10
|
+
<<-RUBY
|
|
11
|
+
value = cache_object(:#{name}, value) { _1&.to_s }
|
|
12
|
+
RUBY
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def globalize
|
|
16
|
+
fail NotImplementedError
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class StringColumn < self
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def code_for_conversion
|
|
10
|
+
<<-RUBY
|
|
11
|
+
value = cache_object(:#{name}, value) { _1&.to_s }
|
|
12
|
+
RUBY
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class SymbolColumn < self
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def code_for_conversion
|
|
10
|
+
<<-RUBY
|
|
11
|
+
value = value&.to_s&.to_sym
|
|
12
|
+
RUBY
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def code_for_sql_value
|
|
16
|
+
<<-RUBY
|
|
17
|
+
#{name}&.to_s
|
|
18
|
+
RUBY
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SimpleMaster
|
|
4
|
+
class Master
|
|
5
|
+
class Column
|
|
6
|
+
class TimeColumn < self
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def code_for_conversion
|
|
10
|
+
<<-RUBY
|
|
11
|
+
value = cache_object(:#{name}, value) { |value|
|
|
12
|
+
if value.is_a?(String)
|
|
13
|
+
#{"value = value.sub(/\A\d{4}-\d\d-\d\d(?:T|\s)|/, \"2000-01-01 \")" if options[:db_type] == :time}
|
|
14
|
+
time_hash = ::Date._parse(value)
|
|
15
|
+
zone = time_hash[:offset] || "UTC"
|
|
16
|
+
value = Time.new(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec), zone)
|
|
17
|
+
end
|
|
18
|
+
value = value.floor if value && value.subsec != 0
|
|
19
|
+
value
|
|
20
|
+
}
|
|
21
|
+
RUBY
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def code_for_sql_value
|
|
25
|
+
if options[:db_type] == :time
|
|
26
|
+
<<-RUBY
|
|
27
|
+
#{name}&.getutc&.strftime('%H:%M:%S')
|
|
28
|
+
RUBY
|
|
29
|
+
else
|
|
30
|
+
<<-RUBY
|
|
31
|
+
#{name}&.getutc&.strftime('%Y-%m-%d %H:%M:%S')
|
|
32
|
+
RUBY
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|