Module: Protobuf::Mongoid::Transformation::ClassMethods

Defined in:
lib/protobuf/mongoid/transformation.rb

Overview

Class Methods

Instance Method Summary collapse

Instance Method Details

#_filter_attribute_fields(proto) ⇒ Object

Filters accessible attributes that exist in the given protobuf message’s fields or have attribute transformers defined for them.

Returns a hash of attribute fields with their respective values.

:nodoc: TODO: Assignment Branch Condition size for _filter_attribute_fields is too high. [<13, 26, 9> 30.43/17] TODO: Use ‘each_with_object` instead of `inject`.



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
# File 'lib/protobuf/mongoid/transformation.rb', line 35

def _filter_attribute_fields(proto)
  fields = proto.to_hash
  fields.select! do |key, _value|
    field = proto.class.get_field(key, true)
    proto.field?(key) && !field.repeated?
  end

  filtered_attributes = _filtered_attributes + _protobuf_attribute_transformers.keys

  attribute_fields = filtered_attributes.inject({}) do |hash, field_name|
    symbolized_field = field_name.to_sym

    if fields.key?(symbolized_field) || _protobuf_attribute_transformers.key?(symbolized_field)
      hash[symbolized_field] = fields[symbolized_field]
    end

    hash
  end

  _protobuf_nested_attributes.each do |attribute_name|
    nested_attribute_name = "#{attribute_name}_attributes".to_sym
    value = if proto.field?(nested_attribute_name)
              proto.__send__(nested_attribute_name)
            elsif proto.field?(attribute_name)
              proto.__send__(attribute_name)
            end

    next unless value

    attribute_fields[nested_attribute_name] = value
  end

  attribute_fields
end

#_filtered_attributesObject

Overidden by mass assignment security when protected attributes is loaded.

:nodoc:



73
74
75
# File 'lib/protobuf/mongoid/transformation.rb', line 73

def _filtered_attributes
  return self.attribute_names
end

#_protobuf_convert_fields_to_attributes(key, value) ⇒ Object

:nodoc:



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/protobuf/mongoid/transformation.rb', line 78

def _protobuf_convert_fields_to_attributes(key, value)
  return nil if value.nil?
  return value unless _protobuf_date_datetime_time_or_timestamp_field?(key)

  value = case
          when _protobuf_datetime_field?(key) then
            convert_int64_to_datetime(value)
          when _protobuf_timestamp_field?(key) then
            convert_int64_to_time(value)
          when _protobuf_time_field?(key) then
            convert_int64_to_time(value)
          when _protobuf_date_field?(key) then
            convert_int64_to_date(value)
          end

  return value
end

#attribute_from_proto(attribute, *args, &block) ⇒ Object

Define an attribute transformation from protobuf. Accepts a Symbol, callable, or block.

When given a callable or block, it is directly used to convert the field.

When a symbol is given, it extracts the method with the same name.

The callable or method must accept a single parameter, which is the proto message.

Examples:

attribute_from_proto :public_key, :extract_public_key_from_proto
attribute_from_proto :status, lambda { |proto| # Do some stuff... }
attribute_from_proto :status do |proto|
  # Do some blocky stuff...
end

attribute_from_proto :status, lambda { |proto| nil }, :nullify_on => :status
attribute_from_proto :status, :nullify_on => :status do |proto|
  nil
end


118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/protobuf/mongoid/transformation.rb', line 118

def attribute_from_proto(attribute, *args, &block)
  options = args.extract_options!
  symbol_or_block = args.first || block

  if symbol_or_block.is_a?(Symbol)
    callable = lambda { |value| self.__send__(symbol_or_block, value) }
  else
    raise AttributeTransformerError unless symbol_or_block.respond_to?(:call)
    callable = symbol_or_block
  end

  if options[:nullify_on]
    field = protobuf_message.get_field(:nullify)
    unless field&.is_a?(::Protobuf::Field::StringField) && field&.repeated?
      ::Protobuf::Logging.logger.warn "Message: #{protobuf_message} is not compatible with :nullify_on option"
    end
  end

  transformer = ::Protobuf::Mongoid::Transformer.new(callable, options)
  _protobuf_attribute_transformers[attribute.to_sym] = transformer
end

#attributes_from_proto(proto) ⇒ Object

Creates a hash of attributes from a given protobuf message.

It converts and transforms field values using the field converters and attribute transformers, ignoring repeated and nil fields.



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/protobuf/mongoid/transformation.rb', line 145

def attributes_from_proto(proto)
  attribute_fields = _filter_attribute_fields(proto)

  attributes = attribute_fields.inject({}) do |hash, (key, value)|
    if _protobuf_attribute_transformers.key?(key)
      transformer = _protobuf_attribute_transformers[key]
      attribute = transformer.call(proto)
      hash[key] = attribute unless attribute.nil?
      hash[key] = nil if transformer.nullify?(proto)
    else
      hash[key] = _protobuf_convert_fields_to_attributes(key, value)
    end

    hash
  end

  # Ensure attributes specified in the `nullify` field are set to nil
  if proto.field?(:nullify) && proto.nullify.is_a?(Array)
    proto.nullify.each do |attribute_name|
      attributes[attribute_name.to_sym] = nil if attribute_fields.key?(attribute_name.to_sym)
    end
  end

  attributes
end

#convert_int64_to_date(int64) ⇒ Object

:nodoc:



177
178
179
# File 'lib/protobuf/mongoid/transformation.rb', line 177

def convert_int64_to_date(int64)
  convert_int64_to_time(int64).utc.to_date
end

#convert_int64_to_datetime(int64) ⇒ Object

:nodoc:



182
183
184
# File 'lib/protobuf/mongoid/transformation.rb', line 182

def convert_int64_to_datetime(int64)
  convert_int64_to_time(int64).to_datetime
end

#convert_int64_to_time(int64) ⇒ Object

:nodoc:



172
173
174
# File 'lib/protobuf/mongoid/transformation.rb', line 172

def convert_int64_to_time(int64)
  Time.at(int64.to_i)
end