class MicrosoftGraph class BaseEntity < Base attr_accessor :graph attr_accessor :parent def initialize(options = {}) @resource_name = options[:resource_name] @parent = options[:parent] || options[:graph] @graph = options[:graph] || parent && parent.graph @navigation_property_name = options[:navigation_property_name] @persisted = options[:persisted] || false super end def parental_chain if parent && parent.respond_to?(:parental_chain) parent.parental_chain.concat([parent]) else [parent] end end def containing_navigation_property(type_name) candidate_navigation_properties = navigation_properties.values.select do |navigation_property| navigation_property.collection? && navigation_property.type.name == "Collection(#{type_name})" end candidate_navigation_properties.sort { |a, b| a_index = type_name.downcase.index(a.name[0..-2].downcase) || 0 b_index = type_name.downcase.index(b.name[0..-2].downcase) || 0 a_index <=> b_index }.last end def path containing_navigation_property_name = nil owning_ancestor = parental_chain.find do |ancestor| unless MicrosoftGraph::CollectionAssociation === ancestor containing_navigation_property = ancestor.containing_navigation_property(odata_type) containing_navigation_property && containing_navigation_property_name = containing_navigation_property.name end end if owning_ancestor && @cached_property_values[:id] [owning_ancestor.path, containing_navigation_property_name, @cached_property_values[:id]].compact.join("/") else @resource_name end end def fetch @persisted = true initialize_serialized_properties(graph.service.get(path)[:attributes]) end def persisted? @persisted end def delete! if persisted? @persisted = false graph.service.delete(path) end end def reload! @dirty_properties.keys.each do |dirty_property| @cached_property_values[dirty_property] = nil end mark_clean fetch if persisted? end def save! raise NoAssociationError unless parent raise_no_graph_error! unless graph if persisted? graph.service.patch(path, to_json(only: @dirty_properties.keys, convert_to_camel_case: true)) else initialize_serialized_properties( graph.service.post(parent.path, to_json(convert_to_camel_case: true)) ) @persisted = true end mark_clean true end def save save! rescue OData::HTTPError false end private def raise_no_graph_error! raise NoGraphError.new("#{self.class}#graph must be a MicrosoftGraph instance to make network requests.") end def get(property_name) if uncached_property?(property_name) && graph initialize_serialized_properties(graph.service.get(path, property_name.to_s)[:attributes], true) super else super end end def get_navigation_property(navigation_property_name) raise_no_graph_error! unless graph navigation_property = navigation_properties[navigation_property_name] if navigation_property.collection? @cached_navigation_property_values[navigation_property_name] ||= CollectionAssociation.new( graph: graph, type: navigation_properties[navigation_property_name].type, resource_name: OData.convert_to_camel_case(navigation_property_name.to_s), parent: self ) else @cached_navigation_property_values[navigation_property_name] ||= if response = graph.service.get("#{path}/#{OData.convert_to_camel_case(navigation_property_name.to_s)}") type = graph.service.get_type_for_odata_response(response[:attributes]) || navigation_property.type klass = ClassBuilder.get_namespaced_class(type.name) klass.new( graph: graph, parent: self, attributes: response[:attributes], persisted: true, navigation_property_name: navigation_property_name.to_s ) else nil end end end def set_navigation_property(navigation_property_name, value) navigation_property = navigation_properties[navigation_property_name] raise TypeError unless navigation_property.type_match?(value) value.parent = self @cached_navigation_property_values[navigation_property_name] = value end def uncached_property?(property) properties.keys.include?(property) && ! @cached_property_values.keys.include?(property) end end end