Class: OData4::Entity

Inherits:
Object
  • Object
show all
Defined in:
lib/odata4/entity.rb

Overview

An OData4::Entity represents a single record returned by the service. All Entities have a type and belong to a specific namespace. They are written back to the service via the EntitySet they came from. OData4::Entity instances should not be instantiated directly; instead, they should either be read or instantiated from their respective OData4::EntitySet.

Constant Summary collapse

PROPERTY_NOT_LOADED =
:not_loaded
XML_NAMESPACES =
{
  'xmlns'           => 'http://www.w3.org/2005/Atom',
  'xmlns:data'      => 'http://docs.oasis-open.org/odata/ns/data',
  'xmlns:metadata'  => 'http://docs.oasis-open.org/odata/ns/metadata',
  'xmlns:georss'    => 'http://www.georss.org/georss',
  'xmlns:gml'       => 'http://www.opengis.net/gml',
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Entity

Initializes a bare Entity

Parameters:

  • options (Hash) (defaults to: {})


31
32
33
34
35
36
37
38
39
40
# File 'lib/odata4/entity.rb', line 31

def initialize(options = {})
  @id = options[:id]
  @type = options[:type]
  @namespace = options[:namespace]
  @service_name = options[:service_name]
  @entity_set = options[:entity_set]
  @context = options[:context]
  @links = options[:links]
  @errors = []
end

Instance Attribute Details

#entity_setObject (readonly)

The entity set this entity belongs to



15
16
17
# File 'lib/odata4/entity.rb', line 15

def entity_set
  @entity_set
end

#errorsObject (readonly)

List of errors on entity



17
18
19
# File 'lib/odata4/entity.rb', line 17

def errors
  @errors
end

#namespaceObject (readonly)

The OData4::Service’s namespace



11
12
13
# File 'lib/odata4/entity.rb', line 11

def namespace
  @namespace
end

#service_nameObject (readonly)

The OData4::Service’s identifying name



13
14
15
# File 'lib/odata4/entity.rb', line 13

def service_name
  @service_name
end

#typeObject (readonly)

The Entity type name



9
10
11
# File 'lib/odata4/entity.rb', line 9

def type
  @type
end

Class Method Details

.from_json(json, options = {}) ⇒ OData4::Entity

Create Entity from JSON document with provided options.

Parameters:

  • json (Hash|to_s)
  • options (Hash) (defaults to: {})

Returns:



143
144
145
146
147
148
149
150
151
# File 'lib/odata4/entity.rb', line 143

def self.from_json(json, options = {})
  return nil if json.nil?
  json = JSON.parse(json.to_s) unless json.is_a?(Hash)
   = (json)
  options.merge!(context: ['@odata.context'])
  entity = with_properties(json, options)
  (entity, )
  entity
end

.from_xml(xml_doc, options = {}) ⇒ OData4::Entity

Create Entity from XML document with provided options.

Parameters:

  • xml_doc (Nokogiri::XML)
  • options (Hash) (defaults to: {})

Returns:



157
158
159
160
161
162
163
# File 'lib/odata4/entity.rb', line 157

def self.from_xml(xml_doc, options = {})
  return nil if xml_doc.nil?
  entity = OData4::Entity.new(options)
  process_properties(entity, xml_doc)
  process_links(entity, xml_doc)
  entity
end

.with_properties(new_properties = {}, options = {}) ⇒ Object

Create Entity with provided properties and options.

Parameters:

  • new_properties (Hash) (defaults to: {})
  • options (Hash) (defaults to: {})
  • (OData4::Entity)


125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/odata4/entity.rb', line 125

def self.with_properties(new_properties = {}, options = {})
  entity = OData4::Entity.new(options)
  entity.instance_eval do
    service.properties_for_entity(name).each do |property_name, instance|
      set_property(property_name, instance)
    end

    new_properties.each do |property_name, property_value|
      self[property_name] = property_value
    end
  end
  entity
end

Instance Method Details

#[](property_name) ⇒ *

Get property value

Parameters:

  • property_name (to_s)

Returns:

  • (*)


57
58
59
60
61
62
63
# File 'lib/odata4/entity.rb', line 57

def [](property_name)
  if get_property(property_name).is_a?(::OData4::ComplexType::Property)
    get_property(property_name)
  else
    get_property(property_name).value
  end
end

#[]=(property_name, value) ⇒ Object

Set property value

Parameters:

  • property_name (to_s)
  • value (*)


68
69
70
# File 'lib/odata4/entity.rb', line 68

def []=(property_name, value)
  get_property(property_name).value = value
end

#any_errors?Boolean

Returns:

  • (Boolean)


223
224
225
# File 'lib/odata4/entity.rb', line 223

def any_errors?
  !errors.empty?
end

#contextString

Returns context URL for this entity

Returns:

  • (String)


50
51
52
# File 'lib/odata4/entity.rb', line 50

def context
  @context ||= context_url
end

#get_property(property_name) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/odata4/entity.rb', line 72

def get_property(property_name)
  prop_name = property_name.to_s
  # Property is lazy loaded
  if properties_xml_value.has_key?(prop_name)
    property = instantiate_property(prop_name, properties_xml_value[prop_name])
    set_property(prop_name, property.dup)
    properties_xml_value.delete(prop_name)
  end

  if properties.has_key? prop_name
    properties[prop_name]
  elsif navigation_properties.has_key? prop_name
    navigation_properties[prop_name]
  else
    raise ArgumentError, "Unknown property: #{property_name}"
  end
end

#idString

Returns the canonical URL for this entity

Returns:

  • (String)


205
206
207
208
209
210
211
# File 'lib/odata4/entity.rb', line 205

def id
  @id ||= lambda {
    entity_set = self.entity_set.andand.name
    entity_set ||= context.split('#').last.split('/').first
    "#{entity_set}(#{self[primary_key]})"
  }.call
end

#is_new?Boolean

Returns:

  • (Boolean)


219
220
221
# File 'lib/odata4/entity.rb', line 219

def is_new?
  self[primary_key].nil?
end

Links to other OData4 entitites

Returns:

  • (Hash)


112
113
114
115
116
117
118
119
# File 'lib/odata4/entity.rb', line 112

def links
  @links ||= service.navigation_properties[name].map do |nav_name, details|
    [
      nav_name,
      { type: details.nav_type, href: "#{id}/#{nav_name}" }
    ]
  end.to_h
end

#nameString

Returns name of Entity from Service specified type.

Returns:

  • (String)


44
45
46
# File 'lib/odata4/entity.rb', line 44

def name
  @name ||= type.gsub(/#{namespace}\./, '')
end


101
102
103
104
105
106
107
108
# File 'lib/odata4/entity.rb', line 101

def navigation_properties
  @navigation_properties ||= links.keys.map do |nav_name|
    [
      nav_name,
      OData4::NavigationProperty::Proxy.new(self, nav_name)
    ]
  end.to_h
end


97
98
99
# File 'lib/odata4/entity.rb', line 97

def navigation_property_names
  navigation_properties.keys
end

#primary_keyString

Returns the primary key for the Entity.

Returns:

  • (String)


215
216
217
# File 'lib/odata4/entity.rb', line 215

def primary_key
  service.primary_key_for(name)
end

#property_namesObject



90
91
92
93
94
95
# File 'lib/odata4/entity.rb', line 90

def property_names
  [
    @properties_xml_value.andand.keys,
    @properties.andand.keys
  ].compact.flatten
end

#serviceObject



227
228
229
# File 'lib/odata4/entity.rb', line 227

def service
  @service ||= OData4::ServiceRegistry[service_name]
end

#to_hashHash

Converts Entity to a hash.

Returns:

  • (Hash)


197
198
199
200
201
# File 'lib/odata4/entity.rb', line 197

def to_hash
  property_names.map do |name|
    [name, get_property(name).json_value]
  end.to_h
end

#to_jsonString

Converts Entity to its JSON representation.

Returns:

  • (String)


190
191
192
193
# File 'lib/odata4/entity.rb', line 190

def to_json
  # TODO: add @odata.context
  to_hash.to_json
end

#to_xmlString

Converts Entity to its XML representation.

Returns:

  • (String)


167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/odata4/entity.rb', line 167

def to_xml
  namespaces = XML_NAMESPACES.merge('xml:base' => service.service_url)
  builder = Nokogiri::XML::Builder.new do |xml|
    xml.entry(namespaces) do
      xml.category(term: "#{namespace}.#{type}",
                   scheme: 'http://docs.oasis-open.org/odata/ns/scheme')
      xml.author { xml.name }

      xml.content(type: 'application/xml') do
        xml['metadata'].properties do
          property_names.each do |name|
            next if name == primary_key
            get_property(name).to_xml(xml)
          end
        end
      end
    end
  end
  builder.to_xml
end