Class: Perpetuity::Postgres::Serializer

Inherits:
Object
  • Object
show all
Includes:
DataInjectable
Defined in:
lib/perpetuity/postgres/serializer.rb

Constant Summary collapse

SERIALIZABLE_CLASSES =
Set[Fixnum, Float, String, Time, Date, TrueClass, FalseClass, NilClass]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(mapper) ⇒ Serializer

Returns a new instance of Serializer.



18
19
20
21
# File 'lib/perpetuity/postgres/serializer.rb', line 18

def initialize mapper
  @mapper = mapper
  @mapper_registry = mapper.mapper_registry if mapper
end

Instance Attribute Details

#mapperObject (readonly)

Returns the value of attribute mapper.



16
17
18
# File 'lib/perpetuity/postgres/serializer.rb', line 16

def mapper
  @mapper
end

#mapper_registryObject (readonly)

Returns the value of attribute mapper_registry.



16
17
18
# File 'lib/perpetuity/postgres/serializer.rb', line 16

def mapper_registry
  @mapper_registry
end

Instance Method Details

#attribute_for(object, attr_name) ⇒ Object



104
105
106
# File 'lib/perpetuity/postgres/serializer.rb', line 104

def attribute_for object, attr_name
  object.instance_variable_get("@#{attr_name}")
end

#foreign_object?(value) ⇒ Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/perpetuity/postgres/serializer.rb', line 80

def foreign_object? value
  value.is_a?(Hash) && value.has_key?('__metadata__')
end

#possible_json_value?(value) ⇒ Boolean

Returns:

  • (Boolean)


76
77
78
# File 'lib/perpetuity/postgres/serializer.rb', line 76

def possible_json_value? value
  value.is_a?(String) && %w([ {).include?(value[0])
end

#serialize(object) ⇒ Object



23
24
25
26
27
28
29
30
31
32
# File 'lib/perpetuity/postgres/serializer.rb', line 23

def serialize object
  attrs = mapper.attribute_set.map do |attribute|
    attr_name = attribute.name.to_s
    value = ValueWithAttribute.new(attribute_for(object, attr_name), attribute)
    serialize_attribute(value)
  end
  column_names = mapper.attributes

  SerializedData.new(column_names, attrs)
end

#serialize_array(object) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/perpetuity/postgres/serializer.rb', line 124

def serialize_array object
  value = object.value rescue object
  array = value.map do |item|
    if SERIALIZABLE_CLASSES.include? item.class
      item
    elsif object.embedded?
      serialize_with_foreign_mapper item
    else
      serialize_reference item
    end
  end

  JSONArray.new(array)
end

#serialize_attribute(object) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/perpetuity/postgres/serializer.rb', line 108

def serialize_attribute object
  value = object.value rescue object

  if SERIALIZABLE_CLASSES.include? value.class
    SQLValue.new(value)
  elsif value.is_a? Array
    serialize_array(object)
  elsif value.is_a? Hash
    serialize_hash(object)
  elsif !object.embedded?
    serialize_reference(value)
  elsif object.embedded?
    serialize_with_foreign_mapper(value)
  end.to_s
end

#serialize_changes(modified, original) ⇒ Object



183
184
185
# File 'lib/perpetuity/postgres/serializer.rb', line 183

def serialize_changes modified, original
  serialize(modified) - serialize(original)
end

#serialize_hash(object) ⇒ Object



139
140
141
# File 'lib/perpetuity/postgres/serializer.rb', line 139

def serialize_hash object
  JSONHash.new(object)
end

#serialize_reference(value) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/perpetuity/postgres/serializer.rb', line 153

def serialize_reference value
  klass = if value.is_a? Reference
            value.klass
          else
            value.class
          end

  unless mapper.persisted? value
    mapper_registry[value.class].insert value
  end

  json = {
    __metadata__: {
      class: klass,
      id: mapper.id_for(value)
    }
  }

  JSONHash.new(json)
end

#serialize_to_hash(value) ⇒ Object



143
144
145
146
147
148
149
150
151
# File 'lib/perpetuity/postgres/serializer.rb', line 143

def serialize_to_hash value
  Hash[
    mapper.attribute_set.map do |attribute|
      attr_name = attribute.name
      attr_value = attribute_for(value, attr_name)
      [attr_name, attr_value]
    end
  ]
end

#serialize_with_foreign_mapper(value) ⇒ Object



174
175
176
177
178
179
180
181
# File 'lib/perpetuity/postgres/serializer.rb', line 174

def serialize_with_foreign_mapper value
  mapper = mapper_registry[value.class]
  serializer = Serializer.new(mapper)
  attr = serializer.serialize_to_hash(value)
  attr.merge!('__metadata__' => { 'class' => value.class })

  JSONHash.new(attr)
end

#serializer_for(klass) ⇒ Object



100
101
102
# File 'lib/perpetuity/postgres/serializer.rb', line 100

def serializer_for klass
  Serializer.new(mapper_registry[klass])
end

#unserialize(data) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/perpetuity/postgres/serializer.rb', line 34

def unserialize data
  if data.is_a? Array
    data.map do |datum|
      object = mapper.mapped_class.allocate
      datum.each do |attribute_name, value|
        attribute = mapper.attribute_set[attribute_name.to_sym]
        deserialized_value = unserialize_attribute(attribute, value)
        inject_attribute object, attribute_name, deserialized_value
      end

      object
    end
  else
    unserialize([data]).first
  end
end

#unserialize_attribute(attribute, value) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/perpetuity/postgres/serializer.rb', line 51

def unserialize_attribute attribute, value
  if value
    if possible_json_value?(value)
      value = JSON.parse(value) rescue value
      if value.is_a? Array
        value = value.map { |v| unserialize_attribute(attribute, v) }
      end
    end
    if foreign_object? value
      value = unserialize_foreign_object value
    end
    if attribute
      if [Fixnum, Bignum, Integer].include? attribute.type
        value = value.to_i
      elsif attribute.type == Time
        value = TimestampValue.from_sql(value).to_time
      elsif [TrueClass, FalseClass].include? attribute.type
        value = value.downcase.start_with? 't'
      end
    end

    value
  end
end

#unserialize_foreign_object(data) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/perpetuity/postgres/serializer.rb', line 84

def unserialize_foreign_object data
   = data.delete('__metadata__')
  klass = Object.const_get(['class'])
  if .has_key? 'id'
    id = ['id']
    return unserialize_reference(klass, id)
  end

  serializer = serializer_for(klass)
  serializer.unserialize(data)
end

#unserialize_reference(klass, id) ⇒ Object



96
97
98
# File 'lib/perpetuity/postgres/serializer.rb', line 96

def unserialize_reference klass, id
  Reference.new(klass, id)
end