activegraph 11.5.0.alpha.1 → 12.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -1
- data/Gemfile +0 -4
- data/activegraph.gemspec +3 -4
- data/lib/active_graph/base.rb +4 -0
- data/lib/active_graph/core/element.rb +142 -0
- data/lib/active_graph/core/entity.rb +4 -0
- data/lib/active_graph/core/label.rb +5 -166
- data/lib/active_graph/core/node.rb +0 -4
- data/lib/active_graph/core/query_clauses.rb +4 -4
- data/lib/active_graph/core/schema.rb +23 -28
- data/lib/active_graph/core/type.rb +13 -0
- data/lib/active_graph/migrations/helpers/schema.rb +10 -13
- data/lib/active_graph/model_schema.rb +1 -1
- data/lib/active_graph/node/has_n.rb +6 -2
- data/lib/active_graph/node/labels.rb +15 -12
- data/lib/active_graph/node/persistence.rb +0 -11
- data/lib/active_graph/node/query/query_proxy/link.rb +15 -4
- data/lib/active_graph/node/query/query_proxy.rb +3 -3
- data/lib/active_graph/node/query/query_proxy_eager_loading.rb +1 -1
- data/lib/active_graph/node/query/query_proxy_enumerable.rb +4 -4
- data/lib/active_graph/node/query/query_proxy_methods.rb +14 -16
- data/lib/active_graph/node/query/query_proxy_methods_of_mass_updating.rb +2 -5
- data/lib/active_graph/node/query.rb +1 -1
- data/lib/active_graph/node/query_methods.rb +9 -12
- data/lib/active_graph/railtie.rb +13 -0
- data/lib/active_graph/relationship/initialize.rb +2 -2
- data/lib/active_graph/relationship/persistence.rb +3 -1
- data/lib/active_graph/relationship/property.rb +1 -5
- data/lib/active_graph/relationship/query.rb +14 -9
- data/lib/active_graph/relationship/related_node.rb +4 -8
- data/lib/active_graph/relationship/types.rb +8 -0
- data/lib/active_graph/relationship/wrapping.rb +1 -1
- data/lib/active_graph/relationship.rb +4 -1
- data/lib/active_graph/shared/identity.rb +6 -3
- data/lib/active_graph/shared/persistence.rb +12 -1
- data/lib/active_graph/shared/query_factory.rb +1 -1
- data/lib/active_graph/shared/type_converters.rb +3 -2
- data/lib/active_graph/transactions.rb +4 -0
- data/lib/active_graph/version.rb +1 -1
- data/lib/active_graph.rb +2 -14
- data/lib/{active_graph/generators → rails/generators/active_graph/migration}/migration_generator.rb +5 -2
- data/lib/{active_graph/generators → rails/generators/active_graph/model}/model_generator.rb +5 -2
- data/lib/{active_graph/generators → rails/generators/active_graph/upgrade_v8}/upgrade_v8_generator.rb +5 -2
- data/lib/{active_graph → rails}/generators/migration_helper.rb +57 -0
- data/lib/{active_graph → rails}/generators/source_path_helper.rb +1 -1
- metadata +34 -54
- data/lib/active_graph/generators/active_model.rb +0 -33
- data/lib/active_graph/generators/generated_attribute.rb +0 -17
- /data/lib/{active_graph/generators → rails/generators/active_graph}/migration/templates/migration.erb +0 -0
- /data/lib/{active_graph/generators → rails/generators/active_graph}/model/templates/migration.erb +0 -0
- /data/lib/{active_graph/generators → rails/generators/active_graph}/model/templates/model.erb +0 -0
- /data/lib/{active_graph/generators → rails/generators/active_graph}/upgrade_v8/templates/migration.erb +0 -0
| @@ -108,7 +108,7 @@ module ActiveGraph | |
| 108 108 |  | 
| 109 109 | 
             
                    # Deletes all nodes and connected relationships from Cypher.
         | 
| 110 110 | 
             
                    def delete_all
         | 
| 111 | 
            -
                      neo4j_query("MATCH (n:`#{mapped_label_name}`)  | 
| 111 | 
            +
                      neo4j_query("MATCH (n:`#{mapped_label_name}`) DETACH DELETE n")
         | 
| 112 112 | 
             
                    end
         | 
| 113 113 |  | 
| 114 114 | 
             
                    # Returns each node to Ruby and calls `destroy`. Be careful, as this can be a very slow operation if you have many nodes. It will generate at least
         | 
| @@ -127,11 +127,15 @@ module ActiveGraph | |
| 127 127 | 
             
                      @mapped_label_name || label_for_model
         | 
| 128 128 | 
             
                    end
         | 
| 129 129 |  | 
| 130 | 
            +
                    alias mapped_element_name mapped_label_name
         | 
| 131 | 
            +
             | 
| 130 132 | 
             
                    # @return [ActiveGraph::Label] the label for this class
         | 
| 131 133 | 
             
                    def mapped_label
         | 
| 132 134 | 
             
                      ActiveGraph::Core::Label.new(mapped_label_name)
         | 
| 133 135 | 
             
                    end
         | 
| 134 136 |  | 
| 137 | 
            +
                    alias mapped_element mapped_label
         | 
| 138 | 
            +
             | 
| 135 139 | 
             
                    def base_class
         | 
| 136 140 | 
             
                      unless self < ActiveGraph::Node
         | 
| 137 141 | 
             
                        fail "#{name} doesn't belong in a hierarchy descending from Node"
         | 
| @@ -160,6 +164,7 @@ module ActiveGraph | |
| 160 164 |  | 
| 161 165 | 
             
                      self.mapped_label_name = name
         | 
| 162 166 | 
             
                    end
         | 
| 167 | 
            +
             | 
| 163 168 | 
             
                    # rubocop:enable Naming/AccessorMethodName
         | 
| 164 169 |  | 
| 165 170 | 
             
                    private
         | 
| @@ -184,20 +189,18 @@ module ActiveGraph | |
| 184 189 | 
             
                    end
         | 
| 185 190 |  | 
| 186 191 | 
             
                    def label_for_model
         | 
| 187 | 
            -
                       | 
| 192 | 
            +
                      name.nil? ? object_id.to_s.to_sym : decorated_label_name
         | 
| 188 193 | 
             
                    end
         | 
| 189 194 |  | 
| 190 195 | 
             
                    def decorated_label_name
         | 
| 191 | 
            -
                       | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
             | 
| 200 | 
            -
                      name.to_sym
         | 
| 196 | 
            +
                      case ActiveGraph::Config[:module_handling]
         | 
| 197 | 
            +
                      when :demodulize
         | 
| 198 | 
            +
                        name.demodulize
         | 
| 199 | 
            +
                      when Proc
         | 
| 200 | 
            +
                        ActiveGraph::Config[:module_handling].call name
         | 
| 201 | 
            +
                      else
         | 
| 202 | 
            +
                        name
         | 
| 203 | 
            +
                      end.to_sym
         | 
| 201 204 | 
             
                    end
         | 
| 202 205 | 
             
                  end
         | 
| 203 206 | 
             
                end
         | 
| @@ -70,17 +70,6 @@ module ActiveGraph::Node | |
| 70 70 | 
             
                  neo4j_query(query, {props: node_props}, wrap: false).to_a[0][:n]
         | 
| 71 71 | 
             
                end
         | 
| 72 72 |  | 
| 73 | 
            -
                # As the name suggests, this inserts the primary key (id property) into the properties hash.
         | 
| 74 | 
            -
                # The method called here, `default_property_values`, is a holdover from an earlier version of the gem. It does NOT
         | 
| 75 | 
            -
                # contain the default values of properties, it contains the Default Property, which we now refer to as the ID Property.
         | 
| 76 | 
            -
                # It will be deprecated and renamed in a coming refactor.
         | 
| 77 | 
            -
                # @param [Hash] converted_props A hash of properties post-typeconversion, ready for insertion into the DB.
         | 
| 78 | 
            -
                def inject_primary_key!(converted_props)
         | 
| 79 | 
            -
                  self.class.default_property_values(self).tap do |destination_props|
         | 
| 80 | 
            -
                    destination_props.merge!(converted_props) if converted_props.is_a?(Hash)
         | 
| 81 | 
            -
                  end
         | 
| 82 | 
            -
                end
         | 
| 83 | 
            -
             | 
| 84 73 | 
             
                # @return [Array] Labels to be set on the node during a create event
         | 
| 85 74 | 
             
                def labels_for_create
         | 
| 86 75 | 
             
                  self.class.mapped_label_names
         | 
| @@ -147,8 +147,8 @@ module ActiveGraph | |
| 147 147 |  | 
| 148 148 | 
             
                          val = if !model
         | 
| 149 149 | 
             
                                  value
         | 
| 150 | 
            -
                                elsif key == model.id_property_name | 
| 151 | 
            -
                                  value | 
| 150 | 
            +
                                elsif key == model.id_property_name
         | 
| 151 | 
            +
                                  try_id(value)
         | 
| 152 152 | 
             
                                else
         | 
| 153 153 | 
             
                                  converted_value(model, key, value)
         | 
| 154 154 | 
             
                                end
         | 
| @@ -156,13 +156,24 @@ module ActiveGraph | |
| 156 156 | 
             
                          new(:where, ->(v, _) { {v => {key => val}} })
         | 
| 157 157 | 
             
                        end
         | 
| 158 158 |  | 
| 159 | 
            +
                        private def try_id(value)
         | 
| 160 | 
            +
                          case value
         | 
| 161 | 
            +
                          when Shared::Identity
         | 
| 162 | 
            +
                            value.id
         | 
| 163 | 
            +
                          when Enumerable
         | 
| 164 | 
            +
                            value.map(&method(:try_id))
         | 
| 165 | 
            +
                          else
         | 
| 166 | 
            +
                            value
         | 
| 167 | 
            +
                          end
         | 
| 168 | 
            +
                        end
         | 
| 169 | 
            +
             | 
| 159 170 | 
             
                        def for_association(name, value, n_string, model)
         | 
| 160 171 | 
             
                          neo_id = value.try(:neo_id) || value
         | 
| 161 | 
            -
                          fail ArgumentError, "Invalid value for '#{name}' condition"  | 
| 172 | 
            +
                          fail ArgumentError, "Invalid value for '#{name}' condition" unless neo_id.is_a?(String)
         | 
| 162 173 |  | 
| 163 174 | 
             
                          [
         | 
| 164 175 | 
             
                            new(:match, ->(v, _) { "(#{v})#{model.associations[name].arrow_cypher}(#{n_string})" }),
         | 
| 165 | 
            -
                            new(:where, ->(_, _) { {" | 
| 176 | 
            +
                            new(:where, ->(_, _) { {"elementId(#{n_string})" => neo_id} })
         | 
| 166 177 | 
             
                          ]
         | 
| 167 178 | 
             
                        end
         | 
| 168 179 |  | 
| @@ -223,7 +223,7 @@ module ActiveGraph | |
| 223 223 |  | 
| 224 224 | 
             
                      ActiveGraph::Base.transaction do
         | 
| 225 225 | 
             
                        other_nodes.each do |other_node|
         | 
| 226 | 
            -
                          if other_node. | 
| 226 | 
            +
                          if other_node.element_id
         | 
| 227 227 | 
             
                            other_node.try(:delete_reverse_has_one_core_rel, association)
         | 
| 228 228 | 
             
                          else
         | 
| 229 229 | 
             
                            other_node.save
         | 
| @@ -238,7 +238,7 @@ module ActiveGraph | |
| 238 238 |  | 
| 239 239 | 
             
                    def _nodeify!(*args)
         | 
| 240 240 | 
             
                      other_nodes = [args].flatten!.map! do |arg|
         | 
| 241 | 
            -
                         | 
| 241 | 
            +
                        arg.is_a?(String) ? @model.find_by(id: arg) : arg
         | 
| 242 242 | 
             
                      end.compact
         | 
| 243 243 |  | 
| 244 244 | 
             
                      if @model && other_nodes.any? { |other_node| !other_node.class.mapped_label_names.include?(@model.mapped_label_name) }
         | 
| @@ -351,7 +351,7 @@ module ActiveGraph | |
| 351 351 | 
             
                      fail 'Crazy error' if !(start_object || @query_proxy)
         | 
| 352 352 |  | 
| 353 353 | 
             
                      if start_object
         | 
| 354 | 
            -
                        :"#{start_object.class.name.gsub('::', '_').downcase}#{start_object.neo_id}"
         | 
| 354 | 
            +
                        :"#{start_object.class.name.gsub('::', '_').downcase}#{start_object.neo_id&.gsub(/[:\-]/, '_')}"
         | 
| 355 355 | 
             
                      else
         | 
| 356 356 | 
             
                        @query_proxy.node_var || :"node#{_chain_level}"
         | 
| 357 357 | 
             
                      end
         | 
| @@ -62,7 +62,7 @@ module ActiveGraph | |
| 62 62 | 
             
                      if rel.is_a?(ActiveGraph::Relationship)
         | 
| 63 63 | 
             
                        rel.instance_variable_set(direction == :in ? '@from_node' : '@to_node', node)
         | 
| 64 64 | 
             
                      end
         | 
| 65 | 
            -
                      @_cache[direction == :out ? rel. | 
| 65 | 
            +
                      @_cache[direction == :out ? rel.start_node_element_id : rel.end_node_element_id]
         | 
| 66 66 | 
             
                        .association_proxy(element.name).add_to_cache(node, rel)
         | 
| 67 67 | 
             
                    end
         | 
| 68 68 |  | 
| @@ -62,22 +62,22 @@ module ActiveGraph | |
| 62 62 | 
             
                    # Does exactly what you would hope. Without it, comparing `bobby.lessons == sandy.lessons` would evaluate to false because it
         | 
| 63 63 | 
             
                    # would be comparing the QueryProxy objects, not the lessons themselves.
         | 
| 64 64 | 
             
                    def ==(other)
         | 
| 65 | 
            -
                       | 
| 65 | 
            +
                      to_a == other
         | 
| 66 66 | 
             
                    end
         | 
| 67 67 |  | 
| 68 68 | 
             
                    # For getting variables which have been defined as part of the association chain
         | 
| 69 69 | 
             
                    def pluck(*args)
         | 
| 70 | 
            -
                      transformable_attributes = (model ? model.attribute_names : []) + %w(uuid neo_id)
         | 
| 70 | 
            +
                      transformable_attributes = (model ? model.attribute_names + [model.id_property_name.to_s] : []) + %w(uuid neo_id)
         | 
| 71 71 | 
             
                      arg_list = args.map do |arg|
         | 
| 72 72 | 
             
                        arg = ActiveGraph::Node::Query::QueryProxy::Link.converted_key(model, arg)
         | 
| 73 73 | 
             
                        if transformable_attributes.include?(arg.to_s)
         | 
| 74 | 
            -
                          {identity => arg}
         | 
| 74 | 
            +
                          { identity => arg }
         | 
| 75 75 | 
             
                        else
         | 
| 76 76 | 
             
                          arg
         | 
| 77 77 | 
             
                        end
         | 
| 78 78 | 
             
                      end
         | 
| 79 79 |  | 
| 80 | 
            -
                       | 
| 80 | 
            +
                      query.pluck(*arg_list)
         | 
| 81 81 | 
             
                    end
         | 
| 82 82 |  | 
| 83 83 | 
             
                    protected
         | 
| @@ -88,7 +88,7 @@ module ActiveGraph | |
| 88 88 | 
             
                    def include?(other, target = nil)
         | 
| 89 89 | 
             
                      query_with_target(target) do |var|
         | 
| 90 90 | 
             
                        where_filter = if other.respond_to?(:neo_id) || association_id_key == :neo_id
         | 
| 91 | 
            -
                                         " | 
| 91 | 
            +
                                         "elementId(#{var}) = $other_node_id"
         | 
| 92 92 | 
             
                                       else
         | 
| 93 93 | 
             
                                         "#{var}.#{association_id_key} = $other_node_id"
         | 
| 94 94 | 
             
                                       end
         | 
| @@ -99,12 +99,12 @@ module ActiveGraph | |
| 99 99 | 
             
                    end
         | 
| 100 100 |  | 
| 101 101 | 
             
                    def exists?(node_condition = nil, target = nil)
         | 
| 102 | 
            -
                      unless [ | 
| 102 | 
            +
                      unless [String, Hash, NilClass].any? { |c| node_condition.is_a?(c) }
         | 
| 103 103 | 
             
                        fail(ActiveGraph::InvalidParameterError, ':exists? only accepts ids or conditions')
         | 
| 104 104 | 
             
                      end
         | 
| 105 105 | 
             
                      query_with_target(target) do |var|
         | 
| 106 106 | 
             
                        start_q = exists_query_start(node_condition, var)
         | 
| 107 | 
            -
                        result = start_q.query.reorder.return(" | 
| 107 | 
            +
                        result = start_q.query.reorder.return("elementId(#{var}) AS proof_of_life LIMIT 1").first
         | 
| 108 108 | 
             
                        !!result
         | 
| 109 109 | 
             
                      end
         | 
| 110 110 | 
             
                    end
         | 
| @@ -119,9 +119,9 @@ module ActiveGraph | |
| 119 119 | 
             
                    def match_to(node)
         | 
| 120 120 | 
             
                      first_node = node.is_a?(Array) ? node.first : node
         | 
| 121 121 | 
             
                      where_arg = if first_node.respond_to?(:neo_id)
         | 
| 122 | 
            -
                                    {neo_id: node.is_a?(Array) ? node.map(&:neo_id) : node}
         | 
| 122 | 
            +
                                    { neo_id: node.is_a?(Array) ? node.map(&:neo_id) : node }
         | 
| 123 123 | 
             
                                  elsif !node.nil?
         | 
| 124 | 
            -
                                    {association_id_key => node.is_a?(Array) ? ids_array(node) : node}
         | 
| 124 | 
            +
                                    { association_id_key => node.is_a?(Array) ? ids_array(node) : node }
         | 
| 125 125 | 
             
                                  else
         | 
| 126 126 | 
             
                                    # support for null object pattern
         | 
| 127 127 | 
             
                                    '1 = 2'
         | 
| @@ -130,7 +130,6 @@ module ActiveGraph | |
| 130 130 | 
             
                      self.where(where_arg)
         | 
| 131 131 | 
             
                    end
         | 
| 132 132 |  | 
| 133 | 
            -
             | 
| 134 133 | 
             
                    # Gives you the first relationship between the last link of a QueryProxy chain and a given node
         | 
| 135 134 | 
             
                    # Shorthand for `MATCH (start)-[r]-(other_node) WHERE ID(other_node) = #{other_node.neo_id} RETURN r`
         | 
| 136 135 | 
             
                    # @param [#neo_id, String, Enumerable] node An object to be sent to `match_to`. See params for that method.
         | 
| @@ -145,6 +144,7 @@ module ActiveGraph | |
| 145 144 | 
             
                    def rels_to(node)
         | 
| 146 145 | 
             
                      self.match_to(node).pluck(rel_var)
         | 
| 147 146 | 
             
                    end
         | 
| 147 | 
            +
             | 
| 148 148 | 
             
                    alias all_rels_to rels_to
         | 
| 149 149 |  | 
| 150 150 | 
             
                    # When called, this method returns a single node that satisfies the match specified in the params hash.
         | 
| @@ -260,7 +260,7 @@ module ActiveGraph | |
| 260 260 | 
             
                                                [self.query.with(identity),
         | 
| 261 261 | 
             
                                                 proc { |var| "#{func}(COLLECT(#{var})) as #{var}" }]
         | 
| 262 262 | 
             
                                              else
         | 
| 263 | 
            -
                                                ord_prop = (func == LAST ? {order_property => :DESC} : order_property)
         | 
| 263 | 
            +
                                                ord_prop = (func == LAST ? { order_property => :DESC } : order_property)
         | 
| 264 264 | 
             
                                                [self.order(ord_prop).limit(1),
         | 
| 265 265 | 
             
                                                 proc { |var| var }]
         | 
| 266 266 | 
             
                                              end
         | 
| @@ -285,16 +285,14 @@ module ActiveGraph | |
| 285 285 | 
             
                      yield(target || identity)
         | 
| 286 286 | 
             
                    end
         | 
| 287 287 |  | 
| 288 | 
            -
                    def exists_query_start(condition, target)
         | 
| 289 | 
            -
                       | 
| 290 | 
            -
                       | 
| 291 | 
            -
             | 
| 292 | 
            -
                       | 
| 293 | 
            -
                         | 
| 294 | 
            -
                      when String
         | 
| 295 | 
            -
                        self.where(model.primary_key => condition)
         | 
| 288 | 
            +
                    def exists_query_start(condition, target = nil)
         | 
| 289 | 
            +
                      return self unless condition
         | 
| 290 | 
            +
                      return exists_query_start(model.primary_key => condition) if condition.is_a?(String)
         | 
| 291 | 
            +
             | 
| 292 | 
            +
                      if condition.key?(:neo_id)
         | 
| 293 | 
            +
                        where("elementId(#{target}) = $neo_id").params(**condition.slice(:neo_id))
         | 
| 296 294 | 
             
                      else
         | 
| 297 | 
            -
                         | 
| 295 | 
            +
                        where(**condition)
         | 
| 298 296 | 
             
                      end
         | 
| 299 297 | 
             
                    end
         | 
| 300 298 | 
             
                  end
         | 
| @@ -25,11 +25,7 @@ module ActiveGraph | |
| 25 25 | 
             
                    # @param identifier [String,Symbol] the optional identifier of the link in the chain to delete.
         | 
| 26 26 | 
             
                    def delete_all(identifier = nil)
         | 
| 27 27 | 
             
                      query_with_target(identifier) do |target|
         | 
| 28 | 
            -
                         | 
| 29 | 
            -
                          self.query.with(target).optional_match("(#{target})-[#{target}_rel]-()").delete("#{target}, #{target}_rel").exec
         | 
| 30 | 
            -
                        rescue Neo4j::Driver::Exceptions::ClientException # <=- Seems hacky
         | 
| 31 | 
            -
                          self.query.delete(target).exec
         | 
| 32 | 
            -
                        end
         | 
| 28 | 
            +
                        query.detach_delete(target).exec
         | 
| 33 29 | 
             
                        clear_source_object_cache
         | 
| 34 30 | 
             
                      end
         | 
| 35 31 | 
             
                    end
         | 
| @@ -51,6 +47,7 @@ module ActiveGraph | |
| 51 47 | 
             
                    def replace_with(node_or_nodes)
         | 
| 52 48 | 
             
                      node_or_nodes = Array(node_or_nodes).map { |arg| arg.is_a?(ActiveGraph::Node) ? arg : @model.find(arg) }
         | 
| 53 49 | 
             
                      original_ids = self.pluck(:id)
         | 
| 50 | 
            +
                      ActiveGraph::Base.lock_node(start_object) unless start_object.new_record?
         | 
| 54 51 | 
             
                      delete_rels_for_nodes(original_ids, node_or_nodes.collect(&:id))
         | 
| 55 52 | 
             
                      add_rels(node_or_nodes, original_ids)
         | 
| 56 53 | 
             
                    end
         | 
| @@ -16,7 +16,7 @@ module ActiveGraph | |
| 16 16 | 
             
                  # @param node_var [Symbol, String] The variable name to specify in the query
         | 
| 17 17 | 
             
                  # @return [ActiveGraph::Core::Query]
         | 
| 18 18 | 
             
                  def query_as(node_var)
         | 
| 19 | 
            -
                    self.class.query_as(node_var, false).where(" | 
| 19 | 
            +
                    self.class.query_as(node_var, false).where("elementId(#{node_var})" => neo_id)
         | 
| 20 20 | 
             
                  end
         | 
| 21 21 |  | 
| 22 22 | 
             
                  # Starts a new QueryProxy with the starting identifier set to the given argument and QueryProxy source_object set to the node instance.
         | 
| @@ -2,12 +2,12 @@ module ActiveGraph | |
| 2 2 | 
             
              module Node
         | 
| 3 3 | 
             
                module QueryMethods
         | 
| 4 4 | 
             
                  def exists?(node_condition = nil)
         | 
| 5 | 
            -
                    unless [ | 
| 5 | 
            +
                    unless [String, Hash, NilClass].any? { |c| node_condition.is_a?(c) }
         | 
| 6 6 | 
             
                      fail(ActiveGraph::InvalidParameterError, ':exists? only accepts ids or conditions')
         | 
| 7 7 | 
             
                    end
         | 
| 8 8 | 
             
                    query_start = exists_query_start(node_condition)
         | 
| 9 9 | 
             
                    start_q = query_start.respond_to?(:query_as) ? query_start.query_as(:n) : query_start
         | 
| 10 | 
            -
                    result = start_q.return(' | 
| 10 | 
            +
                    result = start_q.return('elementId(n) AS proof_of_life LIMIT 1').first
         | 
| 11 11 | 
             
                    !!result
         | 
| 12 12 | 
             
                  end
         | 
| 13 13 |  | 
| @@ -18,7 +18,7 @@ module ActiveGraph | |
| 18 18 |  | 
| 19 19 | 
             
                  # Returns the last node of this class, sorted by ID. Note that this may not be the first node created since Neo4j recycles IDs.
         | 
| 20 20 | 
             
                  def last
         | 
| 21 | 
            -
                    self.query_as(:n).limit(1).order(n: {primary_key => :desc}).pluck(:n).first
         | 
| 21 | 
            +
                    self.query_as(:n).limit(1).order(n: { primary_key => :desc }).pluck(:n).first
         | 
| 22 22 | 
             
                  end
         | 
| 23 23 |  | 
| 24 24 | 
             
                  # @return [Integer] number of nodes of this class
         | 
| @@ -51,16 +51,13 @@ module ActiveGraph | |
| 51 51 |  | 
| 52 52 | 
             
                  private
         | 
| 53 53 |  | 
| 54 | 
            -
                  def exists_query_start( | 
| 55 | 
            -
                     | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
                      self.query_as(:n).where(n: {primary_key => node_condition})
         | 
| 60 | 
            -
                    when Hash
         | 
| 61 | 
            -
                      self.where(node_condition.keys.first => node_condition.values.first)
         | 
| 54 | 
            +
                  def exists_query_start(condition)
         | 
| 55 | 
            +
                    return exists_query_start(primary_key => condition) if condition&.is_a?(String)
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    if condition&.key?(:neo_id)
         | 
| 58 | 
            +
                      query_as(:n).where('elementId(n)' => condition[:neo_id])
         | 
| 62 59 | 
             
                    else
         | 
| 63 | 
            -
                       | 
| 60 | 
            +
                      where(**condition)
         | 
| 64 61 | 
             
                    end
         | 
| 65 62 | 
             
                  end
         | 
| 66 63 | 
             
                end
         | 
    
        data/lib/active_graph/railtie.rb
    CHANGED
    
    | @@ -1,3 +1,16 @@ | |
| 1 | 
            +
            require 'active_graph'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            if defined?(Rails)
         | 
| 4 | 
            +
              # Need the action_dispatch railtie to have action_dispatch.rescue_responses initialized correctly
         | 
| 5 | 
            +
              require 'action_dispatch/railtie'
         | 
| 6 | 
            +
              require 'rails/generators'
         | 
| 7 | 
            +
              require 'rails/generators/active_model'
         | 
| 8 | 
            +
              require 'rails/generators/named_base'
         | 
| 9 | 
            +
              require 'rails/railtie'
         | 
| 10 | 
            +
              require File.expand_path('../rails/generators/migration_helper.rb', __dir__)
         | 
| 11 | 
            +
              Rails::Generators::GeneratedAttribute.include ActiveGraph::Generators::GeneratedAttribute
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 1 14 | 
             
            module ActiveGraph
         | 
| 2 15 | 
             
              class Railtie < ::Rails::Railtie
         | 
| 3 16 | 
             
                def empty_config
         | 
| @@ -19,8 +19,8 @@ module ActiveGraph::Relationship | |
| 19 19 | 
             
                def init_on_reload(unwrapped_reloaded)
         | 
| 20 20 | 
             
                  @attributes = nil
         | 
| 21 21 | 
             
                  init_on_load(unwrapped_reloaded,
         | 
| 22 | 
            -
                               unwrapped_reloaded. | 
| 23 | 
            -
                               unwrapped_reloaded. | 
| 22 | 
            +
                               unwrapped_reloaded.start_node_element_id,
         | 
| 23 | 
            +
                               unwrapped_reloaded.end_node_element_id,
         | 
| 24 24 | 
             
                               unwrapped_reloaded.type)
         | 
| 25 25 | 
             
                  self
         | 
| 26 26 | 
             
                end
         | 
| @@ -5,7 +5,9 @@ module ActiveGraph::Relationship | |
| 5 5 | 
             
                include ActiveGraph::Shared::Persistence
         | 
| 6 6 |  | 
| 7 7 | 
             
                class RelInvalidError < RuntimeError; end
         | 
| 8 | 
            +
             | 
| 8 9 | 
             
                class ModelClassInvalidError < RuntimeError; end
         | 
| 10 | 
            +
             | 
| 9 11 | 
             
                class RelCreateFailedError < RuntimeError; end
         | 
| 10 12 |  | 
| 11 13 | 
             
                def from_node_identifier
         | 
| @@ -84,7 +86,7 @@ module ActiveGraph::Relationship | |
| 84 86 | 
             
                  end
         | 
| 85 87 |  | 
| 86 88 | 
             
                  def query_as(neo_id, var = :r)
         | 
| 87 | 
            -
                    ActiveGraph::Base.new_query.match("()-[#{var}]->()").where(var => {neo_id:  | 
| 89 | 
            +
                    ActiveGraph::Base.new_query.match("()-[#{var}]->()").where(var => { neo_id: })
         | 
| 88 90 | 
             
                  end
         | 
| 89 91 | 
             
                end
         | 
| 90 92 |  | 
| @@ -15,7 +15,7 @@ module ActiveGraph::Relationship | |
| 15 15 | 
             
                alias end_node to_node
         | 
| 16 16 |  | 
| 17 17 | 
             
                %w(start_node end_node).each do |direction|
         | 
| 18 | 
            -
                  define_method("#{direction} | 
| 18 | 
            +
                  define_method("#{direction}_element_id") { send(direction).neo_id if direction }
         | 
| 19 19 | 
             
                end
         | 
| 20 20 |  | 
| 21 21 | 
             
                # @return [String] a string representing the relationship type that will be created
         | 
| @@ -45,10 +45,6 @@ module ActiveGraph::Relationship | |
| 45 45 | 
             
                    end
         | 
| 46 46 | 
             
                  end
         | 
| 47 47 |  | 
| 48 | 
            -
                  def id_property_name
         | 
| 49 | 
            -
                    false
         | 
| 50 | 
            -
                  end
         | 
| 51 | 
            -
             | 
| 52 48 | 
             
                  %w(to_class from_class).each do |direction|
         | 
| 53 49 | 
             
                    define_method(direction.to_s) do |argument = nil|
         | 
| 54 50 | 
             
                      if !argument.nil?
         | 
| @@ -6,18 +6,17 @@ module ActiveGraph::Relationship | |
| 6 6 |  | 
| 7 7 | 
             
                module ClassMethods
         | 
| 8 8 | 
             
                  # Returns the object with the specified neo4j id.
         | 
| 9 | 
            -
                  # @param [String | 
| 9 | 
            +
                  # @param [String] id of node to find
         | 
| 10 10 | 
             
                  def find(id)
         | 
| 11 | 
            -
                    fail "Unknown argument #{id.class} in find method (expected String  | 
| 12 | 
            -
                    find_by_id(id)
         | 
| 11 | 
            +
                    fail "Unknown argument #{id.class} in find method (expected String)" unless [Integer, String].any?(&id.method(:is_a?))
         | 
| 12 | 
            +
                    find_by_id(id) || fail(RecordNotFound.new("Couldn't find #{name} with 'id'=#{id.inspect}", name, id))
         | 
| 13 13 | 
             
                  end
         | 
| 14 14 |  | 
| 15 15 | 
             
                  # Loads the relationship using its neo_id.
         | 
| 16 16 | 
             
                  def find_by_id(key)
         | 
| 17 17 | 
             
                    query = ActiveGraph::Base.new_query
         | 
| 18 | 
            -
                    result = query.match('()-[r]-()').where( | 
| 19 | 
            -
                     | 
| 20 | 
            -
                    result[:r]
         | 
| 18 | 
            +
                    result = query.match('()-[r]-()').where("r.#{id_property_name}" => key).limit(1).return(:r).first
         | 
| 19 | 
            +
                    result&.send(:[], :r)
         | 
| 21 20 | 
             
                  end
         | 
| 22 21 |  | 
| 23 22 | 
             
                  # Performs a very basic match on the relationship.
         | 
| @@ -29,6 +28,10 @@ module ActiveGraph::Relationship | |
| 29 28 | 
             
                    where_query.where(where_string(args)).pluck(:r1)
         | 
| 30 29 | 
             
                  end
         | 
| 31 30 |  | 
| 31 | 
            +
                  def find_by(args)
         | 
| 32 | 
            +
                    where(args).first
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 32 35 | 
             
                  # Performs a basic match on the relationship, returning all results.
         | 
| 33 36 | 
             
                  # This is not executed lazily, it will immediately return matching objects.
         | 
| 34 37 | 
             
                  def all
         | 
| @@ -36,11 +39,11 @@ module ActiveGraph::Relationship | |
| 36 39 | 
             
                  end
         | 
| 37 40 |  | 
| 38 41 | 
             
                  def first
         | 
| 39 | 
            -
                    all_query.limit(1).order(' | 
| 42 | 
            +
                    all_query.limit(1).order('r1.created_at').pluck(:r1).first
         | 
| 40 43 | 
             
                  end
         | 
| 41 44 |  | 
| 42 45 | 
             
                  def last
         | 
| 43 | 
            -
                    all_query.limit(1).order(' | 
| 46 | 
            +
                    all_query.limit(1).order('r1.created_at DESC').pluck(:r1).first
         | 
| 44 47 | 
             
                  end
         | 
| 45 48 |  | 
| 46 49 | 
             
                  private
         | 
| @@ -89,7 +92,9 @@ module ActiveGraph::Relationship | |
| 89 92 | 
             
                  def where_string(args)
         | 
| 90 93 | 
             
                    case args
         | 
| 91 94 | 
             
                    when Hash
         | 
| 92 | 
            -
                      args. | 
| 95 | 
            +
                      args.transform_keys { |key| key == :neo_id ? 'elementId(r1)' : "r1.#{key}" }
         | 
| 96 | 
            +
                          .transform_values { |v| v.is_a?(Integer) ? v : "'#{v}'" }
         | 
| 97 | 
            +
                          .map { |k, v| "#{k} = #{v}" }.join(', ')
         | 
| 93 98 | 
             
                    else
         | 
| 94 99 | 
             
                      args
         | 
| 95 100 | 
             
                    end
         | 
| @@ -17,7 +17,7 @@ module ActiveGraph::Relationship | |
| 17 17 |  | 
| 18 18 | 
             
                # Loads the node if needed, then conducts comparison.
         | 
| 19 19 | 
             
                def ==(other)
         | 
| 20 | 
            -
                  loaded if @node.is_a?( | 
| 20 | 
            +
                  loaded if @node.is_a?(String)
         | 
| 21 21 | 
             
                  @node == other
         | 
| 22 22 | 
             
                end
         | 
| 23 23 |  | 
| @@ -62,15 +62,11 @@ module ActiveGraph::Relationship | |
| 62 62 | 
             
                end
         | 
| 63 63 |  | 
| 64 64 | 
             
                def method_missing(*args, **kwargs, &block)
         | 
| 65 | 
            -
                   | 
| 66 | 
            -
                    loaded.send(*args, &block)
         | 
| 67 | 
            -
                  else
         | 
| 68 | 
            -
                    loaded.send(*args, **kwargs, &block)
         | 
| 69 | 
            -
                  end
         | 
| 65 | 
            +
                  loaded.send(*args, **kwargs, &block)
         | 
| 70 66 | 
             
                end
         | 
| 71 67 |  | 
| 72 68 | 
             
                def respond_to_missing?(method_name, include_private = false)
         | 
| 73 | 
            -
                  loaded if @node.is_a?( | 
| 69 | 
            +
                  loaded if @node.is_a?(String)
         | 
| 74 70 | 
             
                  @node.respond_to?(method_name) ? true : super
         | 
| 75 71 | 
             
                end
         | 
| 76 72 |  | 
| @@ -85,7 +81,7 @@ module ActiveGraph::Relationship | |
| 85 81 | 
             
                end
         | 
| 86 82 |  | 
| 87 83 | 
             
                def valid_node_param?(node)
         | 
| 88 | 
            -
                  node.nil? || node.is_a?( | 
| 84 | 
            +
                  node.nil? || node.is_a?(String) || node.respond_to?(:neo_id)
         | 
| 89 85 | 
             
                end
         | 
| 90 86 | 
             
              end
         | 
| 91 87 | 
             
            end
         | 
| @@ -10,6 +10,7 @@ module ActiveGraph | |
| 10 10 | 
             
                include ActiveGraph::Relationship::Initialize
         | 
| 11 11 | 
             
                include ActiveGraph::Shared::Identity
         | 
| 12 12 | 
             
                include ActiveGraph::Shared::Marshal
         | 
| 13 | 
            +
                include ActiveGraph::Node::IdProperty
         | 
| 13 14 | 
             
                include ActiveGraph::Shared::SerializedProperties
         | 
| 14 15 | 
             
                include ActiveGraph::Relationship::Property
         | 
| 15 16 | 
             
                include ActiveGraph::Relationship::Persistence
         | 
| @@ -24,6 +25,8 @@ module ActiveGraph | |
| 24 25 | 
             
                class FrozenRelError < ActiveGraph::Error; end
         | 
| 25 26 |  | 
| 26 27 | 
             
                def initialize(from_node = nil, to_node = nil, args = nil)
         | 
| 28 | 
            +
                  self.class.ensure_id_property_info! # So that we make sure all objects have an id_property
         | 
| 29 | 
            +
             | 
| 27 30 | 
             
                  load_nodes(node_or_nil(from_node), node_or_nil(to_node))
         | 
| 28 31 | 
             
                  resolved_args = hash_or_nil(from_node, args)
         | 
| 29 32 | 
             
                  symbol_args = sanitize_input_parameters(resolved_args)
         | 
| @@ -58,7 +61,7 @@ module ActiveGraph | |
| 58 61 | 
             
                private
         | 
| 59 62 |  | 
| 60 63 | 
             
                def node_or_nil(node)
         | 
| 61 | 
            -
                  node.is_a?(ActiveGraph::Node) || node.is_a?( | 
| 64 | 
            +
                  node.is_a?(ActiveGraph::Node) || node.is_a?(String) ? node : nil
         | 
| 62 65 | 
             
                end
         | 
| 63 66 |  | 
| 64 67 | 
             
                def hash_or_nil(node_or_hash, hash_or_nil)
         | 
| @@ -4,6 +4,7 @@ module ActiveGraph | |
| 4 4 | 
             
                  def ==(other)
         | 
| 5 5 | 
             
                    other.class == self.class && other.id == id
         | 
| 6 6 | 
             
                  end
         | 
| 7 | 
            +
             | 
| 7 8 | 
             
                  alias eql? ==
         | 
| 8 9 |  | 
| 9 10 | 
             
                  # Returns an Enumerable of all (primary) key attributes
         | 
| @@ -12,11 +13,13 @@ module ActiveGraph | |
| 12 13 | 
             
                    _persisted_obj ? [id] : nil
         | 
| 13 14 | 
             
                  end
         | 
| 14 15 |  | 
| 15 | 
            -
                  # @return [ | 
| 16 | 
            -
                  def  | 
| 17 | 
            -
                    _persisted_obj | 
| 16 | 
            +
                  # @return [String, nil] the neo4j id of the node if persisted or nil
         | 
| 17 | 
            +
                  def element_id
         | 
| 18 | 
            +
                    _persisted_obj&.element_id
         | 
| 18 19 | 
             
                  end
         | 
| 19 20 |  | 
| 21 | 
            +
                  alias neo_id element_id
         | 
| 22 | 
            +
             | 
| 20 23 | 
             
                  def id
         | 
| 21 24 | 
             
                    if self.class.id_property_name
         | 
| 22 25 | 
             
                      send(self.class.id_property_name)
         | 
| @@ -134,7 +134,7 @@ module ActiveGraph::Shared | |
| 134 134 | 
             
                def exist?
         | 
| 135 135 | 
             
                  return if !_persisted_obj
         | 
| 136 136 |  | 
| 137 | 
            -
                  neo4j_query(query_as(:n).return(' | 
| 137 | 
            +
                  neo4j_query(query_as(:n).return('elementId(n)')).any?
         | 
| 138 138 | 
             
                end
         | 
| 139 139 |  | 
| 140 140 | 
             
                # Returns +true+ if the object was destroyed.
         | 
| @@ -223,6 +223,17 @@ module ActiveGraph::Shared | |
| 223 223 | 
             
                  end
         | 
| 224 224 | 
             
                end
         | 
| 225 225 |  | 
| 226 | 
            +
                # As the name suggests, this inserts the primary key (id property) into the properties hash.
         | 
| 227 | 
            +
                # The method called here, `default_property_values`, is a holdover from an earlier version of the gem. It does NOT
         | 
| 228 | 
            +
                # contain the default values of properties, it contains the Default Property, which we now refer to as the ID Property.
         | 
| 229 | 
            +
                # It will be deprecated and renamed in a coming refactor.
         | 
| 230 | 
            +
                # @param [Hash] converted_props A hash of properties post-typeconversion, ready for insertion into the DB.
         | 
| 231 | 
            +
                def inject_primary_key!(converted_props)
         | 
| 232 | 
            +
                  self.class.default_property_values(self).tap do |destination_props|
         | 
| 233 | 
            +
                    destination_props.merge!(converted_props) if converted_props.is_a?(Hash)
         | 
| 234 | 
            +
                  end
         | 
| 235 | 
            +
                end
         | 
| 236 | 
            +
             | 
| 226 237 | 
             
                protected
         | 
| 227 238 |  | 
| 228 239 | 
             
                def increment_by_query!(match_query, attribute, by, element_name = :n)
         | 
| @@ -47,7 +47,7 @@ module ActiveGraph::Shared | |
| 47 47 |  | 
| 48 48 | 
             
                def match_query
         | 
| 49 49 | 
             
                  base_query
         | 
| 50 | 
            -
                    .match(match_string).where(" | 
| 50 | 
            +
                    .match(match_string).where("elementId(#{identifier}) = $#{identifier_id}")
         | 
| 51 51 | 
             
                    .params(identifier_id.to_sym => graph_object.neo_id)
         | 
| 52 52 | 
             
                end
         | 
| 53 53 |  | 
| @@ -389,7 +389,7 @@ module ActiveGraph::Shared | |
| 389 389 | 
             
                  def included(_)
         | 
| 390 390 | 
             
                    ActiveGraph::Shared::TypeConverters.constants.each do |constant_name|
         | 
| 391 391 | 
             
                      constant = ActiveGraph::Shared::TypeConverters.const_get(constant_name)
         | 
| 392 | 
            -
                      register_converter(constant) if constant.respond_to?(:convert_type)
         | 
| 392 | 
            +
                      register_converter(constant, force: false) if constant.respond_to?(:convert_type)
         | 
| 393 393 | 
             
                    end
         | 
| 394 394 | 
             
                  end
         | 
| 395 395 |  | 
| @@ -425,7 +425,8 @@ module ActiveGraph::Shared | |
| 425 425 | 
             
                    found_converter.respond_to?(:converted?) ? found_converter.converted?(value) : value.is_a?(found_converter.db_type)
         | 
| 426 426 | 
             
                  end
         | 
| 427 427 |  | 
| 428 | 
            -
                  def register_converter(converter)
         | 
| 428 | 
            +
                  def register_converter(converter, force: true)
         | 
| 429 | 
            +
                    return if CONVERTERS.key?(converter.convert_type) && !force
         | 
| 429 430 | 
             
                    CONVERTERS[converter.convert_type] = converter
         | 
| 430 431 | 
             
                  end
         | 
| 431 432 | 
             
                end
         |