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
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5980a6fcd4bee8de9d49abdc805f45292b507d76b6d4299eb3424b57fd33dd98
         | 
| 4 | 
            +
              data.tar.gz: 16a8d463cf9b8cf88d814b4a9fd33db8f83e92b3ab4cd2e903377e420b4acd24
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 02bb5a53486be92a3a8724a42525b02148065fb0461fe9400d31c95d3bf7cbe351028cd955fea96dd22ec587baae8abe6c4e9498d131a7019bbee0bb2c78d093
         | 
| 7 | 
            +
              data.tar.gz: a98acca7075481e24e9926bfcbb8cb6fadefc9e11cef963fa146fc7c543e8682d7fcb8639e681c3fb5971738d01568623f59456cb93ce36de7c0eaf7a6500abf
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -3,10 +3,29 @@ All notable changes to this project will be documented in this file. | |
| 3 3 | 
             
            This file should follow the standards specified on [http://keepachangelog.com/]
         | 
| 4 4 | 
             
            This project adheres to [Semantic Versioning](http://semver.org/).
         | 
| 5 5 |  | 
| 6 | 
            -
            ## [ | 
| 6 | 
            +
            ## [12.0.0.beta.1] 2024-01-01
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            ## Added
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            - removed deprecated usage of id (neo_id), replaced with element_id, requires neo4j-ruby-driver 5
         | 
| 11 | 
            +
            - removed the possibility of using neo_id as id_property
         | 
| 12 | 
            +
            - added id_property to relationships
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            ## [11.5.0.beta.1] 2023-12-29
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            ## Added
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            - migrated to zeitwerk
         | 
| 19 | 
            +
            - rails 7.1 support
         | 
| 7 20 |  | 
| 8 21 | 
             
            ## Fixed
         | 
| 9 22 |  | 
| 23 | 
            +
            - caching of has one relationships
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            ## [11.4.0] 2023-12-02
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            ## Added
         | 
| 28 | 
            +
             | 
| 10 29 | 
             
            - Added support for cypher UNION
         | 
| 11 30 |  | 
| 12 31 | 
             
            ## [11.3.1] 2023-02-12
         | 
    
        data/Gemfile
    CHANGED
    
    | @@ -2,10 +2,6 @@ source 'http://rubygems.org' | |
| 2 2 |  | 
| 3 3 | 
             
            gemspec
         | 
| 4 4 |  | 
| 5 | 
            -
            # gem 'neo4j-ruby-driver', path: '../neo4j-ruby-driver'
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            # gem 'listen', '< 3.1'
         | 
| 8 | 
            -
             | 
| 9 5 | 
             
            active_model_version = ENV['ACTIVE_MODEL_VERSION']
         | 
| 10 6 | 
             
            gem 'activemodel', "~> #{active_model_version}" if active_model_version&.length&.positive?
         | 
| 11 7 |  | 
    
        data/activegraph.gemspec
    CHANGED
    
    | @@ -30,10 +30,9 @@ DESCRIPTION | |
| 30 30 | 
             
                'bug_tracker_uri' => 'https://github.com/neo4jrb/activegraph/issues'
         | 
| 31 31 | 
             
              }
         | 
| 32 32 |  | 
| 33 | 
            -
              s.add_dependency('activemodel', '>=  | 
| 34 | 
            -
              s.add_dependency('activesupport', '>= 4.0')
         | 
| 33 | 
            +
              s.add_dependency('activemodel', '>= 7')
         | 
| 35 34 | 
             
              s.add_dependency('i18n', '!= 1.8.8') # https://github.com/jruby/jruby/issues/6547
         | 
| 36 | 
            -
              s.add_dependency('neo4j-ruby-driver', '>=  | 
| 35 | 
            +
              s.add_dependency('neo4j-ruby-driver', '>= 5')
         | 
| 37 36 | 
             
              s.add_dependency('orm_adapter', '>= 0.5.0')
         | 
| 38 37 | 
             
              s.add_dependency('sorted_set')
         | 
| 39 38 | 
             
              s.add_development_dependency('guard')
         | 
| @@ -42,7 +41,7 @@ DESCRIPTION | |
| 42 41 | 
             
              s.add_development_dependency('neo4j-rake_tasks', '>= 0.3.0')
         | 
| 43 42 | 
             
              s.add_development_dependency('os')
         | 
| 44 43 | 
             
              s.add_development_dependency('pry')
         | 
| 45 | 
            -
              s.add_development_dependency('railties', '>=  | 
| 44 | 
            +
              s.add_development_dependency('railties', '>= 7')
         | 
| 46 45 | 
             
              s.add_development_dependency('rake')
         | 
| 47 46 | 
             
              s.add_development_dependency('rubocop', '>= 0.56.0')
         | 
| 48 47 | 
             
              s.add_development_dependency('yard')
         | 
    
        data/lib/active_graph/base.rb
    CHANGED
    
    | @@ -60,6 +60,10 @@ module ActiveGraph | |
| 60 60 | 
             
                    ActiveGraph::Core::Label.new(label_name)
         | 
| 61 61 | 
             
                  end
         | 
| 62 62 |  | 
| 63 | 
            +
                  def element(name, relationship: false)
         | 
| 64 | 
            +
                    (relationship ? Core::Type : Core::Label).new(name)
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 63 67 | 
             
                  def logger
         | 
| 64 68 | 
             
                    @logger ||= (ActiveGraph::Config[:logger] || ActiveSupport::Logger.new(STDOUT))
         | 
| 65 69 | 
             
                  end
         | 
| @@ -0,0 +1,142 @@ | |
| 1 | 
            +
            module ActiveGraph
         | 
| 2 | 
            +
              module Core
         | 
| 3 | 
            +
                class Element
         | 
| 4 | 
            +
                  attr_reader :name
         | 
| 5 | 
            +
                  delegate :version?, to: ActiveGraph::Base
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def initialize(name)
         | 
| 8 | 
            +
                    @name = name
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def create_index(*properties, **options)
         | 
| 12 | 
            +
                    validate_index_options!(options)
         | 
| 13 | 
            +
                    properties = properties.map { |p| "l.#{p}" }
         | 
| 14 | 
            +
                    schema_query("CREATE INDEX FOR (l:`#{@name}`) ON (#{properties.join('.')})")
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def drop_index(property, options = {})
         | 
| 18 | 
            +
                    validate_index_options!(options)
         | 
| 19 | 
            +
                    schema_query("SHOW INDEXES YIELD * WHERE labelsOrTypes = $labels AND properties = $properties",
         | 
| 20 | 
            +
                                 labels: [@name], properties: [property]).each do |record|
         | 
| 21 | 
            +
                      schema_query("DROP INDEX #{record[:name]}")
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  # Creates a neo4j constraint on a property
         | 
| 26 | 
            +
                  # See http://docs.neo4j.org/chunked/stable/query-constraints.html
         | 
| 27 | 
            +
                  # @example
         | 
| 28 | 
            +
                  #   label = ActiveGraph::Label.create(:person)
         | 
| 29 | 
            +
                  #   label.create_constraint(:name, {type: :unique})
         | 
| 30 | 
            +
                  #
         | 
| 31 | 
            +
                  def create_constraint(property, type: :key)
         | 
| 32 | 
            +
                    schema_query(
         | 
| 33 | 
            +
                      "CREATE CONSTRAINT #{constraint_name(property, type:)} FOR #{pattern("n:`#{name}`")} REQUIRE n.`#{property}` IS #{constraint_type(type:)}"
         | 
| 34 | 
            +
                    )
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # Drops a neo4j constraint on a property
         | 
| 38 | 
            +
                  # See http://docs.neo4j.org/chunked/stable/query-constraints.html
         | 
| 39 | 
            +
                  # @example
         | 
| 40 | 
            +
                  #   label = ActiveGraph::Label.create(:person)
         | 
| 41 | 
            +
                  #   label.create_constraint(:name, {type: :unique})
         | 
| 42 | 
            +
                  #   label.drop_constraint(:name, {type: :unique})
         | 
| 43 | 
            +
                  #
         | 
| 44 | 
            +
                  def drop_constraint(property, type: :key)
         | 
| 45 | 
            +
                    schema_query("DROP CONSTRAINT #{constraint_name(property, type:)} IF EXISTS")
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def drop_uniqueness_constraint(property, options = {})
         | 
| 49 | 
            +
                    drop_constraint(property, type: :unique)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def indexes
         | 
| 53 | 
            +
                    self.class.indexes.select do |definition|
         | 
| 54 | 
            +
                      definition[:label] == @name.to_sym
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  def drop_indexes
         | 
| 59 | 
            +
                    self.class.drop_indexes
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def index?(property)
         | 
| 63 | 
            +
                    indexes.any? { |definition| definition[:properties] == [property.to_sym] }
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  def constraints(_options = {})
         | 
| 67 | 
            +
                    ActiveGraph::Base.constraints.select do |definition|
         | 
| 68 | 
            +
                      definition[:label] == @name.to_sym
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  def uniqueness_constraints(_options = {})
         | 
| 73 | 
            +
                    constraints.select do |definition|
         | 
| 74 | 
            +
                      definition[:type] == :uniqueness
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  def constraint?(property)
         | 
| 79 | 
            +
                    constraints.any? { |definition| definition[:properties] == [property.to_sym] }
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  def uniqueness_constraint?(property)
         | 
| 83 | 
            +
                    uniqueness_constraints.include?([property])
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  private
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  class << self
         | 
| 89 | 
            +
                    def indexes
         | 
| 90 | 
            +
                      ActiveGraph::Base.indexes
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    def drop_indexes
         | 
| 94 | 
            +
                      indexes.each do |definition|
         | 
| 95 | 
            +
                        ActiveGraph::Base.query("DROP INDEX #{definition[:name]}") unless definition[:owningConstraint]
         | 
| 96 | 
            +
                      end
         | 
| 97 | 
            +
                    end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                    def drop_constraints
         | 
| 100 | 
            +
                      result = ActiveGraph::Base.read_transaction do |tx|
         | 
| 101 | 
            +
                        tx.run('SHOW CONSTRAINTS YIELD *').to_a
         | 
| 102 | 
            +
                      end
         | 
| 103 | 
            +
                      ActiveGraph::Base.write_transaction do |tx|
         | 
| 104 | 
            +
                        result.each do |record|
         | 
| 105 | 
            +
                          tx.run("DROP CONSTRAINT `#{record[:name]}`")
         | 
| 106 | 
            +
                        end
         | 
| 107 | 
            +
                      end
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  def schema_query(cypher, **params)
         | 
| 112 | 
            +
                    ActiveGraph::Base.query(cypher, params)
         | 
| 113 | 
            +
                  end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                  def validate_index_options!(options)
         | 
| 116 | 
            +
                    return unless options[:type] && options[:type] != :exact
         | 
| 117 | 
            +
                    fail "Type #{options[:type]} is not supported"
         | 
| 118 | 
            +
                  end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                  def constraint_type(type:)
         | 
| 121 | 
            +
                    case symnolic_type(type:)
         | 
| 122 | 
            +
                    when :key
         | 
| 123 | 
            +
                      "#{element_type} KEY"
         | 
| 124 | 
            +
                    when :unique
         | 
| 125 | 
            +
                      "UNIQUE"
         | 
| 126 | 
            +
                    when :not_null
         | 
| 127 | 
            +
                      "UNIQUE"
         | 
| 128 | 
            +
                    else
         | 
| 129 | 
            +
                      ":: #{type.to_s.upcase}"
         | 
| 130 | 
            +
                    end
         | 
| 131 | 
            +
                  end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                  def symnolic_type(type:)
         | 
| 134 | 
            +
                    type == :key && !ActiveGraph::Base.enterprise? ? :unique : type
         | 
| 135 | 
            +
                  end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                  def constraint_name(property, type:)
         | 
| 138 | 
            +
                    "`#{element_type}_#{name}##{property}_#{symnolic_type(type:)}`"
         | 
| 139 | 
            +
                  end
         | 
| 140 | 
            +
                end
         | 
| 141 | 
            +
              end
         | 
| 142 | 
            +
            end
         | 
| @@ -1,173 +1,12 @@ | |
| 1 1 | 
             
            module ActiveGraph
         | 
| 2 2 | 
             
              module Core
         | 
| 3 | 
            -
                class Label
         | 
| 4 | 
            -
                   | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
                  def initialize(name)
         | 
| 8 | 
            -
                    @name = name
         | 
| 9 | 
            -
                  end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                  def create_index(*properties, **options)
         | 
| 12 | 
            -
                    validate_index_options!(options)
         | 
| 13 | 
            -
                    if version?('>=4.4')
         | 
| 14 | 
            -
                      properties = properties.map { |p| "l.#{p}" }
         | 
| 15 | 
            -
                      fragment = "FOR (l:`#{@name}`) ON"
         | 
| 16 | 
            -
                    else
         | 
| 17 | 
            -
                      fragment = "ON :`#{@name}`"
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                    schema_query("CREATE INDEX #{fragment} (#{properties.join('.')})")
         | 
| 20 | 
            -
                  end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                  def drop_index(property, options = {})
         | 
| 23 | 
            -
                    validate_index_options!(options)
         | 
| 24 | 
            -
                    if version?('<4.3')
         | 
| 25 | 
            -
                      schema_query("DROP INDEX ON :`#{@name}`(#{property})")
         | 
| 26 | 
            -
                    else
         | 
| 27 | 
            -
                      schema_query("SHOW INDEXES YIELD * WHERE labelsOrTypes = $labels AND properties = $properties",
         | 
| 28 | 
            -
                                   labels: [@name], properties: [property]).each do |record|
         | 
| 29 | 
            -
                        schema_query("DROP INDEX #{record[:name]}")
         | 
| 30 | 
            -
                      end
         | 
| 31 | 
            -
                    end
         | 
| 32 | 
            -
                  end
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                  # Creates a neo4j constraint on a property
         | 
| 35 | 
            -
                  # See http://docs.neo4j.org/chunked/stable/query-constraints.html
         | 
| 36 | 
            -
                  # @example
         | 
| 37 | 
            -
                  #   label = ActiveGraph::Label.create(:person)
         | 
| 38 | 
            -
                  #   label.create_constraint(:name, {type: :unique})
         | 
| 39 | 
            -
                  #
         | 
| 40 | 
            -
                  def create_constraint(property, constraints)
         | 
| 41 | 
            -
                    cypher = case constraints[:type]
         | 
| 42 | 
            -
                             when :unique, :uniqueness
         | 
| 43 | 
            -
                               _for, _require = version?('>=4.4') ? %w[FOR REQUIRE] : %w[ON ASSERT]
         | 
| 44 | 
            -
                               "CREATE CONSTRAINT #{_for} (n:`#{name}`) #{_require} n.`#{property}` IS UNIQUE"
         | 
| 45 | 
            -
                             else
         | 
| 46 | 
            -
                               fail "Not supported constraint #{constraints.inspect} for property #{property} (expected :type => :unique)"
         | 
| 47 | 
            -
                             end
         | 
| 48 | 
            -
                    schema_query(cypher)
         | 
| 49 | 
            -
                  end
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                  def create_uniqueness_constraint(property, options = {})
         | 
| 52 | 
            -
                    create_constraint(property, options.merge(type: :unique))
         | 
| 53 | 
            -
                  end
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                  # Drops a neo4j constraint on a property
         | 
| 56 | 
            -
                  # See http://docs.neo4j.org/chunked/stable/query-constraints.html
         | 
| 57 | 
            -
                  # @example
         | 
| 58 | 
            -
                  #   label = ActiveGraph::Label.create(:person)
         | 
| 59 | 
            -
                  #   label.create_constraint(:name, {type: :unique})
         | 
| 60 | 
            -
                  #   label.drop_constraint(:name, {type: :unique})
         | 
| 61 | 
            -
                  #
         | 
| 62 | 
            -
                  def drop_constraint(property, constraint)
         | 
| 63 | 
            -
                    return drop_constraint42(property, constraint) if version?('<4.3')
         | 
| 64 | 
            -
                    type = case constraint[:type]
         | 
| 65 | 
            -
                           when :unique, :uniqueness
         | 
| 66 | 
            -
                             'UNIQUENESS'
         | 
| 67 | 
            -
                           when :exists
         | 
| 68 | 
            -
                             'NODE_PROPERTY_EXISTENCE'
         | 
| 69 | 
            -
                           else
         | 
| 70 | 
            -
                             fail "Not supported constraint #{constraint.inspect}"
         | 
| 71 | 
            -
                           end
         | 
| 72 | 
            -
                    schema_query(
         | 
| 73 | 
            -
                      'SHOW CONSTRAINTS YIELD * WHERE type = $type AND labelsOrTypes = $labels AND properties = $properties',
         | 
| 74 | 
            -
                      type: type, labels: [name], properties: [property]).first[:name].tap do |constraint_name|
         | 
| 75 | 
            -
                      schema_query("DROP CONSTRAINT #{constraint_name}")
         | 
| 76 | 
            -
                    end
         | 
| 77 | 
            -
                  end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                  def drop_uniqueness_constraint(property, options = {})
         | 
| 80 | 
            -
                    drop_constraint(property, options.merge(type: :unique))
         | 
| 81 | 
            -
                  end
         | 
| 82 | 
            -
             | 
| 83 | 
            -
                  def indexes
         | 
| 84 | 
            -
                    self.class.indexes.select do |definition|
         | 
| 85 | 
            -
                      definition[:label] == @name.to_sym
         | 
| 86 | 
            -
                    end
         | 
| 87 | 
            -
                  end
         | 
| 88 | 
            -
             | 
| 89 | 
            -
                  def drop_indexes
         | 
| 90 | 
            -
                    self.class.drop_indexes
         | 
| 91 | 
            -
                  end
         | 
| 92 | 
            -
             | 
| 93 | 
            -
                  def index?(property)
         | 
| 94 | 
            -
                    indexes.any? { |definition| definition[:properties] == [property.to_sym] }
         | 
| 95 | 
            -
                  end
         | 
| 96 | 
            -
             | 
| 97 | 
            -
                  def constraints(_options = {})
         | 
| 98 | 
            -
                    ActiveGraph::Base.constraints.select do |definition|
         | 
| 99 | 
            -
                      definition[:label] == @name.to_sym
         | 
| 100 | 
            -
                    end
         | 
| 101 | 
            -
                  end
         | 
| 102 | 
            -
             | 
| 103 | 
            -
                  def uniqueness_constraints(_options = {})
         | 
| 104 | 
            -
                    constraints.select do |definition|
         | 
| 105 | 
            -
                      definition[:type] == :uniqueness
         | 
| 106 | 
            -
                    end
         | 
| 107 | 
            -
                  end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                  def constraint?(property)
         | 
| 110 | 
            -
                    constraints.any? { |definition| definition[:properties] == [property.to_sym] }
         | 
| 111 | 
            -
                  end
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                  def uniqueness_constraint?(property)
         | 
| 114 | 
            -
                    uniqueness_constraints.include?([property])
         | 
| 115 | 
            -
                  end
         | 
| 116 | 
            -
             | 
| 117 | 
            -
                  private
         | 
| 118 | 
            -
             | 
| 119 | 
            -
                  class << self
         | 
| 120 | 
            -
                    def indexes
         | 
| 121 | 
            -
                      ActiveGraph::Base.indexes
         | 
| 122 | 
            -
                    end
         | 
| 123 | 
            -
             | 
| 124 | 
            -
                    def drop_indexes
         | 
| 125 | 
            -
                      indexes.each do |definition|
         | 
| 126 | 
            -
                        begin
         | 
| 127 | 
            -
                          ActiveGraph::Base.query(
         | 
| 128 | 
            -
                            if definition[:name]
         | 
| 129 | 
            -
                              "DROP INDEX #{definition[:name]}"
         | 
| 130 | 
            -
                            else
         | 
| 131 | 
            -
                              "DROP INDEX ON :`#{definition[:label]}`(#{definition[:properties][0]})"
         | 
| 132 | 
            -
                            end)
         | 
| 133 | 
            -
                        rescue Neo4j::Driver::Exceptions::DatabaseException
         | 
| 134 | 
            -
                          # This will error on each constraint. Ignore and continue.
         | 
| 135 | 
            -
                          next
         | 
| 136 | 
            -
                        end
         | 
| 137 | 
            -
                      end
         | 
| 138 | 
            -
                    end
         | 
| 139 | 
            -
             | 
| 140 | 
            -
                    def drop_constraints
         | 
| 141 | 
            -
                      result = ActiveGraph::Base.read_transaction do |tx|
         | 
| 142 | 
            -
                        tx.run(ActiveGraph::Base.version?('<4.3') ? 'CALL db.constraints' : 'SHOW CONSTRAINTS YIELD *').to_a
         | 
| 143 | 
            -
                      end
         | 
| 144 | 
            -
                      ActiveGraph::Base.write_transaction do |tx|
         | 
| 145 | 
            -
                        result.each do |record|
         | 
| 146 | 
            -
                          tx.run("DROP #{record.keys.include?(:name) ? "CONSTRAINT #{record[:name]}" : record[:description]}")
         | 
| 147 | 
            -
                        end
         | 
| 148 | 
            -
                      end
         | 
| 149 | 
            -
                    end
         | 
| 150 | 
            -
                  end
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                  def schema_query(cypher, **params)
         | 
| 153 | 
            -
                    ActiveGraph::Base.query(cypher, params)
         | 
| 154 | 
            -
                  end
         | 
| 155 | 
            -
             | 
| 156 | 
            -
                  def validate_index_options!(options)
         | 
| 157 | 
            -
                    return unless options[:type] && options[:type] != :exact
         | 
| 158 | 
            -
                    fail "Type #{options[:type]} is not supported"
         | 
| 3 | 
            +
                class Label < Element
         | 
| 4 | 
            +
                  def pattern(spec)
         | 
| 5 | 
            +
                    "(#{spec})"
         | 
| 159 6 | 
             
                  end
         | 
| 160 7 |  | 
| 161 | 
            -
                  def  | 
| 162 | 
            -
                     | 
| 163 | 
            -
                             when :unique, :uniqueness
         | 
| 164 | 
            -
                               "n.`#{property}` IS UNIQUE"
         | 
| 165 | 
            -
                             when :exists
         | 
| 166 | 
            -
                               "exists(n.`#{property}`)"
         | 
| 167 | 
            -
                             else
         | 
| 168 | 
            -
                               fail "Not supported constraint #{constraint.inspect}"
         | 
| 169 | 
            -
                             end
         | 
| 170 | 
            -
                    schema_query("DROP CONSTRAINT ON (n:`#{name}`) ASSERT #{cypher}")
         | 
| 8 | 
            +
                  def element_type
         | 
| 9 | 
            +
                    'NODE'
         | 
| 171 10 | 
             
                  end
         | 
| 172 11 | 
             
                end
         | 
| 173 12 | 
             
              end
         | 
| @@ -158,7 +158,7 @@ module ActiveGraph | |
| 158 158 | 
             
                      end
         | 
| 159 159 |  | 
| 160 160 | 
             
                      def from_key_and_single_value(key, value)
         | 
| 161 | 
            -
                        value.to_sym == :neo_id ? " | 
| 161 | 
            +
                        value.to_sym == :neo_id ? "elementId(#{key})" : "#{key}.#{value}"
         | 
| 162 162 | 
             
                      end
         | 
| 163 163 | 
             
                    end
         | 
| 164 164 |  | 
| @@ -200,7 +200,7 @@ module ActiveGraph | |
| 200 200 | 
             
                    end
         | 
| 201 201 |  | 
| 202 202 | 
             
                    def array_value?(value, is_set)
         | 
| 203 | 
            -
                      value.is_a?( | 
| 203 | 
            +
                      value.is_a?(Enumerable) && !is_set
         | 
| 204 204 | 
             
                    end
         | 
| 205 205 |  | 
| 206 206 | 
             
                    def format_label(label_arg)
         | 
| @@ -316,8 +316,8 @@ module ActiveGraph | |
| 316 316 | 
             
                    def hash_key_value_string(key, value, previous_keys)
         | 
| 317 317 | 
             
                      value.map do |k, v|
         | 
| 318 318 | 
             
                        if k.to_sym == :neo_id
         | 
| 319 | 
            -
                          v = Array(v).map { |item|  | 
| 320 | 
            -
                          key_value_string(" | 
| 319 | 
            +
                          v = Array(v).map { |item| item.respond_to?(:neo_id) ? item.neo_id : item }
         | 
| 320 | 
            +
                          key_value_string("elementId(#{key})", v)
         | 
| 321 321 | 
             
                        else
         | 
| 322 322 | 
             
                          "#{key}.#{from_key_and_value(k, v, previous_keys + [key])}"
         | 
| 323 323 | 
             
                        end
         | 
| @@ -1,21 +1,20 @@ | |
| 1 1 | 
             
            module ActiveGraph
         | 
| 2 2 | 
             
              module Core
         | 
| 3 3 | 
             
                module Schema
         | 
| 4 | 
            -
                  FILTER = {
         | 
| 5 | 
            -
                    3 => [:type, 'node_unique_property'],
         | 
| 6 | 
            -
                    4 => [:uniqueness, 'UNIQUE'],
         | 
| 7 | 
            -
                  }
         | 
| 8 | 
            -
             | 
| 9 4 | 
             
                  def version
         | 
| 10 | 
            -
                     | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
                     | 
| 5 | 
            +
                    Gem::Version.new(component[:versions][0])
         | 
| 6 | 
            +
                  end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  def edition
         | 
| 9 | 
            +
                    component[:edition]
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def enterprise?
         | 
| 13 | 
            +
                    edition == 'enterprise'
         | 
| 15 14 | 
             
                  end
         | 
| 16 15 |  | 
| 17 16 | 
             
                  def version?(requirement)
         | 
| 18 | 
            -
                    Gem::Requirement.create(requirement).satisfied_by?( | 
| 17 | 
            +
                    Gem::Requirement.create(requirement).satisfied_by?(version)
         | 
| 19 18 | 
             
                  end
         | 
| 20 19 |  | 
| 21 20 | 
             
                  def indexes
         | 
| @@ -24,17 +23,12 @@ module ActiveGraph | |
| 24 23 |  | 
| 25 24 | 
             
                  def normalize(result, *extra)
         | 
| 26 25 | 
             
                    result.map do |row|
         | 
| 27 | 
            -
                      definition(row,  | 
| 28 | 
            -
                        .merge(extra.to_h { |key| [key, row[key].to_sym] })
         | 
| 26 | 
            +
                      definition(row, :index_cypher).merge(extra.to_h { |key| [key, row[key].to_sym] })
         | 
| 29 27 | 
             
                    end
         | 
| 30 28 | 
             
                  end
         | 
| 31 29 |  | 
| 32 30 | 
             
                  def constraints
         | 
| 33 | 
            -
                     | 
| 34 | 
            -
                      raw_indexes.select(&method(:constraint_owned?))
         | 
| 35 | 
            -
                    else
         | 
| 36 | 
            -
                      raw_constraints.select(&method(:constraint_filter))
         | 
| 37 | 
            -
                    end.map { |row| definition(row, :constraint_cypher).merge(type: :uniqueness) }
         | 
| 31 | 
            +
                    raw_constraints.select(&method(:constraint_filter)).map { |row| definition(row, :constraint_cypher).merge(type: :uniqueness) }
         | 
| 38 32 | 
             
                  end
         | 
| 39 33 |  | 
| 40 34 | 
             
                  private def raw_constraints
         | 
| @@ -45,27 +39,28 @@ module ActiveGraph | |
| 45 39 |  | 
| 46 40 | 
             
                  def raw_indexes
         | 
| 47 41 | 
             
                    read_transaction do
         | 
| 48 | 
            -
                      query( | 
| 49 | 
            -
                        .reject { |row| row[:type] == 'LOOKUP' }
         | 
| 42 | 
            +
                      query('SHOW INDEXES YIELD *', {}, skip_instrumentation: true).reject { |row| row[:type] == 'LOOKUP' }
         | 
| 50 43 | 
             
                    end
         | 
| 51 44 | 
             
                  end
         | 
| 52 45 |  | 
| 53 46 | 
             
                  def constraint_owned?(record)
         | 
| 54 | 
            -
                     | 
| 47 | 
            +
                    record[:owningConstraint]
         | 
| 55 48 | 
             
                  end
         | 
| 56 49 |  | 
| 57 50 | 
             
                  private
         | 
| 58 51 |  | 
| 52 | 
            +
                  def component
         | 
| 53 | 
            +
                    @component ||= read_transaction do
         | 
| 54 | 
            +
                      query('CALL dbms.components()', {}, skip_instrumentation: true).first
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
             | 
| 59 58 | 
             
                  def major
         | 
| 60 59 | 
             
                    @major ||= version.segments.first
         | 
| 61 60 | 
             
                  end
         | 
| 62 61 |  | 
| 63 62 | 
             
                  def constraint_filter(record)
         | 
| 64 | 
            -
                    %w[UNIQUENESS RELATIONSHIP_PROPERTY_EXISTENCE NODE_PROPERTY_EXISTENCE NODE_KEY].include?(record[:type])
         | 
| 65 | 
            -
                  end
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                  def index_cypher_v3(label, properties)
         | 
| 68 | 
            -
                    "INDEX ON :#{label}#{com_sep(properties, nil)}"
         | 
| 63 | 
            +
                    %w[UNIQUENESS RELATIONSHIP_UNIQUENESS RELATIONSHIP_PROPERTY_EXISTENCE NODE_PROPERTY_EXISTENCE NODE_KEY RELATIONSHIP_KEY].include?(record[:type])
         | 
| 69 64 | 
             
                  end
         | 
| 70 65 |  | 
| 71 66 | 
             
                  def index_cypher(label, properties)
         | 
| @@ -82,11 +77,11 @@ module ActiveGraph | |
| 82 77 |  | 
| 83 78 | 
             
                  def definition(row, template)
         | 
| 84 79 | 
             
                    { label: label(row), properties: properties(row), name: row[:name],
         | 
| 85 | 
            -
                      create_statement: row[:createStatement] || send(template,label(row), row[:properties]) }
         | 
| 80 | 
            +
                      create_statement: row[:createStatement] || send(template, label(row), row[:properties]) }
         | 
| 86 81 | 
             
                  end
         | 
| 87 82 |  | 
| 88 83 | 
             
                  def label(row)
         | 
| 89 | 
            -
                    row[ | 
| 84 | 
            +
                    row[:labelsOrTypes].first.to_sym
         | 
| 90 85 | 
             
                  end
         | 
| 91 86 |  | 
| 92 87 | 
             
                  def properties(row)
         | 
| @@ -6,18 +6,16 @@ module ActiveGraph | |
| 6 6 | 
             
                    MISSING_CONSTRAINT_OR_INDEX = 'No such %{type} for %{label}#%{property}'.freeze
         | 
| 7 7 | 
             
                    DUPLICATE_CONSTRAINT_OR_INDEX = 'Duplicate %{type} for %{label}#%{property}'.freeze
         | 
| 8 8 |  | 
| 9 | 
            -
                    def add_constraint( | 
| 10 | 
            -
                       | 
| 11 | 
            -
                       | 
| 12 | 
            -
                      label_object = ActiveGraph::Base.label_object(label)
         | 
| 13 | 
            -
                      if label_object.constraint?(property)
         | 
| 9 | 
            +
                    def add_constraint(name, property, relationship: false, type: :key, force: false)
         | 
| 10 | 
            +
                      element = ActiveGraph::Base.element(name, relationship:)
         | 
| 11 | 
            +
                      if element.constraint?(property)
         | 
| 14 12 | 
             
                        if force
         | 
| 15 | 
            -
                           | 
| 13 | 
            +
                          element.drop_constraint(property, type:)
         | 
| 16 14 | 
             
                        else
         | 
| 17 | 
            -
                          fail_duplicate_constraint_or_index!(:constraint,  | 
| 15 | 
            +
                          fail_duplicate_constraint_or_index!(:constraint, name, property)
         | 
| 18 16 | 
             
                        end
         | 
| 19 17 | 
             
                      end
         | 
| 20 | 
            -
                       | 
| 18 | 
            +
                      element.create_constraint(property, type:)
         | 
| 21 19 | 
             
                    end
         | 
| 22 20 |  | 
| 23 21 | 
             
                    def add_index(label, property, options = {})
         | 
| @@ -33,11 +31,10 @@ module ActiveGraph | |
| 33 31 | 
             
                      label_object.create_index(property)
         | 
| 34 32 | 
             
                    end
         | 
| 35 33 |  | 
| 36 | 
            -
                    def drop_constraint( | 
| 37 | 
            -
                       | 
| 38 | 
            -
                       | 
| 39 | 
            -
                       | 
| 40 | 
            -
                      label_object.drop_constraint(property, type: type)
         | 
| 34 | 
            +
                    def drop_constraint(name, property, type: :key, relationship: false, force: false)
         | 
| 35 | 
            +
                      element = ActiveGraph::Base.element(name, relationship:)
         | 
| 36 | 
            +
                      fail_missing_constraint_or_index!(:constraint, name, property) unless force || element.constraint?(property)
         | 
| 37 | 
            +
                      element.drop_constraint(property, type:)
         | 
| 41 38 | 
             
                    end
         | 
| 42 39 |  | 
| 43 40 | 
             
                    def drop_index(label, property, options = {})
         | 
| @@ -55,7 +55,7 @@ module ActiveGraph | |
| 55 55 | 
             
                  # should be private
         | 
| 56 56 | 
             
                  def schema_elements_list(by_model, db_results)
         | 
| 57 57 | 
             
                    by_model.flat_map do |model, property_names|
         | 
| 58 | 
            -
                      label = model. | 
| 58 | 
            +
                      label = model.mapped_element_name.to_sym
         | 
| 59 59 | 
             
                      property_names.map do |property_name|
         | 
| 60 60 | 
             
                        exists = db_results[label] && db_results[label].include?([property_name])
         | 
| 61 61 | 
             
                        [model, label, property_name, exists]
         | 
| @@ -111,13 +111,17 @@ module ActiveGraph::Node | |
| 111 111 |  | 
| 112 112 | 
             
                  def add_to_cache(object, rel = nil)
         | 
| 113 113 | 
             
                    (@cached_rels ||= []) << rel if rel
         | 
| 114 | 
            -
                    (@cached_result ||= []).tap { |results| results << object if  | 
| 114 | 
            +
                    (@cached_result ||= []).tap { |results| results << object if !results.include?(object) } if object
         | 
| 115 115 | 
             
                  end
         | 
| 116 116 |  | 
| 117 117 | 
             
                  def rels
         | 
| 118 118 | 
             
                    @cached_rels || super.tap { |rels| rels.each { |rel| add_to_cache(nil, rel)  } }
         | 
| 119 119 | 
             
                  end
         | 
| 120 120 |  | 
| 121 | 
            +
                  def rel
         | 
| 122 | 
            +
                    rels.first
         | 
| 123 | 
            +
                  end
         | 
| 124 | 
            +
             | 
| 121 125 | 
             
                  def cache_query_proxy_result
         | 
| 122 126 | 
             
                    (result_cache_proc_cache || @query_proxy).to_a.tap { |result| cache_result(result) }
         | 
| 123 127 | 
             
                  end
         | 
| @@ -282,7 +286,7 @@ module ActiveGraph::Node | |
| 282 286 | 
             
                  query_proxy = self.class.as(:previous).where(neo_id: result_cache.map(&:neo_id))
         | 
| 283 287 | 
             
                  query_proxy = self.class.send(:association_query_proxy, association_name, previous_query_proxy: query_proxy, node: :next, optional: true)
         | 
| 284 288 |  | 
| 285 | 
            -
                  Hash[*query_proxy.pluck(' | 
| 289 | 
            +
                  Hash[*query_proxy.pluck('elementId(previous)', 'collect(next)').flatten(1)].each_value do |records|
         | 
| 286 290 | 
             
                    records.each do |record|
         | 
| 287 291 | 
             
                      record.instance_variable_set('@source_proxy_result_cache', records)
         | 
| 288 292 | 
             
                    end
         |