-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserialized_columns.rb
96 lines (75 loc) · 2.37 KB
/
serialized_columns.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
module Core
class SerializedColumn < ActiveRecord::ConnectionAdapters::Column
def type_cast(val)
case type
when :array then val.try(:split,',')
else super(val)
end
end
def type_cast_for_write(value)
case value
when Array then value.join(',')
else super(value)
end
end
def simplified_type(field_type)
case field_type
when 'array' then :array
else super(field_type)
end
end
end
module SerializedColumns
extend ActiveSupport::Concern
# ActiveRecord redefines this for names that are in the columns hash (as we override), to
# search in the @attributes list. But obviously, that won't be there for this type of property.
def has_attribute?(attr)
if config = self.class.serialized_columns[attr.to_sym]
super(config.first)
else
super(attr)
end
end
module ClassMethods
def serialized_columns
@serialized_columns ||= {}
end
def store_attribute_columns
serialized_columns.values.map(&:first)
end
def content_columns
super.reject{|c| store_attribute_columns.include? c.name.to_sym }
end
def columns
super + serialized_columns.values.map(&:last)
end
def serialized_accessor store_attribute, name, type, default: nil
sql_type = case type
when :string then 'varchar'
when :double then 'float'
when :time then 'timestamp'
else type.to_s
end
column = SerializedColumn.new name.to_s, default, sql_type
serialized_columns[name] = [store_attribute, column]
define_method name do
raw = read_store_attribute store_attribute, name
column.type_cast(raw)
end
define_method :"#{name}_before_type_cast" do
read_store_attribute store_attribute, name
end
define_method :"#{name}=" do |val|
raw = column.type_cast_for_write(val)
write_store_attribute store_attribute, name, raw
end
scope :"with_#{name}_present", -> do
where{ length(Squeel::Nodes::Stub.new(store_attribute).op('->', name.to_s)) > 0 }
end
scope :"with_#{name}_value", ->(val) do
where{cast(Squeel::Nodes::Stub.new(store_attribute).op('->', name.to_s).as(sql_type)) == val}
end
end
end
end
end