class ActiveGraph::Shared::DeclaredProperties

The DeclaredPropertyuManager holds details about objects created as a result of calling the property class method on a class that includes ActiveGraph::Node or ActiveGraph::Relationship. There are many options that are referenced frequently, particularly during load and save, so this provides easy access and a way of separating behavior from the general Active{obj} modules.

See ActiveGraph::Shared::DeclaredProperty for definitions of the property objects themselves.

Constants

EXCLUDED_TYPES

Attributes

klass[R]

Public Class Methods

new(klass) click to toggle source

Each class that includes ActiveGraph::Node or ActiveGraph::Relationship gets one instance of this class. @param [#declared_properties] klass An object that has the declared_properties method.

   # File lib/active_graph/shared/declared_properties.rb
16 def initialize(klass)
17   @klass = klass
18 end

Public Instance Methods

[](key) click to toggle source
   # File lib/active_graph/shared/declared_properties.rb
20 def [](key)
21   registered_properties[key.to_sym]
22 end
attributes_nil_hash() click to toggle source

During object wrap, a hash is needed that contains each declared property with a nil value. The active_attr dependency is capable of providing this but it is expensive and calculated on the fly each time it is called. Rather than rely on that, we build this progressively as properties are registered. When the node or rel is loaded, this is used as a template.

   # File lib/active_graph/shared/declared_properties.rb
69 def attributes_nil_hash
70   @_attributes_nil_hash ||= {}.tap do |attr_hash|
71     registered_properties.each_pair do |k, prop_obj|
72       val = prop_obj.default_value
73       attr_hash[k.to_s] = val
74     end
75   end.freeze
76 end
attributes_string_map() click to toggle source

During object wrapping, a props hash is built with string keys but ActiveGraph::Core provides symbols. Rather than a `to_s` or `symbolize_keys` during every load, we build a map of symbol-to-string to speed up the process. This increases memory used by the gem but reduces object allocation and GC, so it is faster in practice.

   # File lib/active_graph/shared/declared_properties.rb
82 def attributes_string_map
83   @_attributes_string_map ||= {}.tap do |attr_hash|
84     attributes_nil_hash.each_key { |k| attr_hash[k.to_sym] = k }
85   end.freeze
86 end
constraint_or_fail!(key, id_property_name, type = :unique) click to toggle source
   # File lib/active_graph/shared/declared_properties.rb
45 def constraint_or_fail!(key, id_property_name, type = :unique)
46   return if key == id_property_name
47   fail "Cannot constraint undeclared property #{property}" unless property?(key)
48   registered_properties[key].constraint!(type)
49 end
declared_property_defaults() click to toggle source

The :default option in ActiveGraph::Node#property class method allows for setting a default value instead of nil on declared properties. This holds those values.

   # File lib/active_graph/shared/declared_properties.rb
53 def declared_property_defaults
54   @_default_property_values ||= {}
55 end
index_or_fail!(key, id_property_name, type = :exact) click to toggle source
   # File lib/active_graph/shared/declared_properties.rb
39 def index_or_fail!(key, id_property_name, type = :exact)
40   return if key == id_property_name
41   fail "Cannot index undeclared property #{key}" unless property?(key)
42   registered_properties[key].index!(type)
43 end
indexed_properties() click to toggle source
   # File lib/active_graph/shared/declared_properties.rb
61 def indexed_properties
62   registered_properties.select { |_, p| p.index_or_constraint? }
63 end
inject_defaults!(object, props) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
157 def inject_defaults!(object, props)
158   declared_property_defaults.each_pair do |k, v|
159     props[k.to_sym] = v.respond_to?(:call) ? v.call : v if object.send(k).nil? && props[k.to_sym].nil?
160   end
161   props
162 end
magic_typecast_properties() click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
131 def magic_typecast_properties
132   @magic_typecast_properties ||= {}
133 end
magic_typecast_properties_keys() click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
127 def magic_typecast_properties_keys
128   @magic_typecast_properties_keys ||= magic_typecast_properties.keys
129 end
property?(key) click to toggle source
   # File lib/active_graph/shared/declared_properties.rb
24 def property?(key)
25   registered_properties.key?(key.to_sym)
26 end
register(property) click to toggle source

@param [ActiveGraph::Shared::DeclaredProperty] property An instance of DeclaredProperty, created as the result of calling property on an Node or Relationship class. The DeclaredProperty has specifics about the property, but registration makes the management object aware of it. This is necessary for type conversion, defaults, and inclusion in the nil and string hashes.

   # File lib/active_graph/shared/declared_properties.rb
31 def register(property)
32   @_attributes_nil_hash = nil
33   @_attributes_string_map = nil
34   registered_properties[property.name] = property
35   register_magic_typecaster(property) if property.magic_typecaster
36   declared_property_defaults[property.name] = property.default_value if !property.default_value.nil?
37 end
registered_properties() click to toggle source
   # File lib/active_graph/shared/declared_properties.rb
57 def registered_properties
58   @_registered_properties ||= {}
59 end
serialize(name, coder = JSON) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
109 def serialize(name, coder = JSON)
110   @serialize ||= {}
111   @serialize[name] = coder
112 end
serialized_properties() click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
119 def serialized_properties
120   @serialize ||= {}
121 end
serialized_properties=(serialize_hash) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
114 def serialized_properties=(serialize_hash)
115   @serialized_property_keys = nil
116   @serialize = serialize_hash.clone
117 end
serialized_properties_keys() click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
123 def serialized_properties_keys
124   @serialized_property_keys ||= serialized_properties.keys
125 end
string_key(k) click to toggle source

@param [Symbol] k A symbol for which the String representation is sought. This might seem silly – we could just call to_s – but when this happens many times while loading many objects, it results in a surprisingly significant slowdown. The branching logic handles what happens if a property can't be found. The first option attempts to find it in the existing hash. The second option checks whether the key is the class's id property and, if it is, the string hash is rebuilt with it to prevent future lookups. The third calls `to_s`. This would happen if undeclared properties are found on the object. We could add them to the string map but that would result in unchecked, un-GCed memory consumption. In the event that someone is adding properties dynamically, maybe through user input, this would be bad.

   # File lib/active_graph/shared/declared_properties.rb
97 def string_key(k)
98   attributes_string_map[k] || string_map_id_property(k) || k.to_s
99 end
unregister(name) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
101 def unregister(name)
102   # might need to be include?(name.to_s)
103   fail ArgumentError, "Argument `#{name}` not an attribute" if not registered_properties[name]
104   registered_properties.delete(name)
105   unregister_magic_typecaster(name)
106   unregister_property_default(name)
107 end
value_for_db(key, value) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
147 def value_for_db(key, value)
148   return value unless registered_properties[key]
149   convert_property(key, value, :to_db)
150 end
value_for_ruby(key, value) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
152 def value_for_ruby(key, value)
153   return unless registered_properties[key]
154   convert_property(key, value, :to_ruby)
155 end
value_for_where(key, value) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
136 def value_for_where(key, value)
137   return value unless prop = registered_properties[key]
138   return value_for_db(key, value) if prop.typecaster && prop.typecaster.convert_type == value.class
139 
140   if should_convert_for_where?(key, value)
141     value_for_db(key, value)
142   else
143     value
144   end
145 end

Protected Instance Methods

fetch_upstream_primitive(attr) click to toggle source

Prevents repeated calls to :_attribute_type, which isn't free and never changes.

    # File lib/active_graph/shared/declared_properties.rb
167 def fetch_upstream_primitive(attr)
168   registered_properties[attr].type
169 end

Private Instance Methods

register_magic_typecaster(property) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
199 def register_magic_typecaster(property)
200   magic_typecast_properties[property.name] = property.magic_typecaster
201   @magic_typecast_properties_keys = nil
202 end
should_convert_for_where?(key, value) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
173 def should_convert_for_where?(key, value)
174   (value.is_a?(Array) && supports_array?(key)) || !EXCLUDED_TYPES.include?(value.class)
175 end
string_map_id_property(key) click to toggle source

@param [Symbol] key An undeclared property value found in the _persisted_obj.properties hash. Typically, this is a node's id property, which will not be registered as other properties are. In the future, this should probably be reworked a bit. This class should either not know or care about the id property or it should be in charge of it. In the meantime, this improves node load performance.

    # File lib/active_graph/shared/declared_properties.rb
182 def string_map_id_property(key)
183   return unless klass.id_property_name == key
184   key.to_s.tap do |string_key|
185     @_attributes_string_map = attributes_string_map.dup.tap { |h| h[key] = string_key }.freeze
186   end
187 end
unregister_magic_typecaster(property) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
189 def unregister_magic_typecaster(property)
190   magic_typecast_properties.delete(property)
191   @magic_typecast_properties_keys = nil
192 end
unregister_property_default(property) click to toggle source
    # File lib/active_graph/shared/declared_properties.rb
194 def unregister_property_default(property)
195   declared_property_defaults.delete(property)
196   @_default_property_values = nil
197 end