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
|