activegraph 10.0.0.pre.alpha.7 → 10.0.0.pre.alpha.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/config/neo4j/config.yml +0 -3
- data/lib/neo4j.rb +1 -0
- data/lib/neo4j/active_node.rb +1 -0
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +12 -11
- data/lib/neo4j/active_node/dependent_callbacks.rb +31 -0
- data/lib/neo4j/active_node/has_n.rb +7 -8
- data/lib/neo4j/active_node/query/query_proxy.rb +1 -1
- data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +29 -5
- data/lib/neo4j/active_rel/callbacks.rb +6 -0
- data/lib/neo4j/active_rel/persistence.rb +4 -5
- data/lib/neo4j/migrations/runner.rb +1 -1
- data/lib/neo4j/migrations/schema.rb +21 -1
- data/lib/neo4j/tasks/migration.rake +3 -1
- data/lib/neo4j/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b7846af39d73f89f279284b358f2f4e5552709b6dd8812a5481944fdf479ec0
|
4
|
+
data.tar.gz: 71674f9403e7f9c88ab23631e138e6b901a3ae9dcfb672fbf7277ce20d26c61b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0ed7a4862b179f5b0b02a3dbccc440604ab309e744736247c2d6600848f29387e9ecd4504a6a170a4dcc287be42543d6443d52d8a12ec4544a0b1238af796d5
|
7
|
+
data.tar.gz: fa3b8f1d9db6aa4c5d3d3090dd74a761a9d8c8399f0c1e5fcafeac57a6402b37f3987ee99efcf7a07e9a775b9f1045a574892e340b21d504b11fc39fb663a04e
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,12 @@ 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
|
+
## [10.0.x] 2020-01-23
|
7
|
+
|
8
|
+
- Executing relationship callbacks on relationship deletion.
|
9
|
+
- When assiging relationships, preserving earlier relationships.
|
10
|
+
- Enforcing has one constraint on relationships.
|
11
|
+
|
6
12
|
## [9.6.1] 2019-12-18
|
7
13
|
|
8
14
|
## Fixed
|
data/config/neo4j/config.yml
CHANGED
data/lib/neo4j.rb
CHANGED
@@ -61,6 +61,7 @@ require 'neo4j/active_rel/related_node'
|
|
61
61
|
require 'neo4j/active_rel/types'
|
62
62
|
require 'neo4j/active_rel'
|
63
63
|
|
64
|
+
require 'neo4j/active_node/dependent_callbacks'
|
64
65
|
require 'neo4j/active_node/node_list_formatter'
|
65
66
|
require 'neo4j/active_node/dependent'
|
66
67
|
require 'neo4j/active_node/dependent/query_proxy_methods'
|
data/lib/neo4j/active_node.rb
CHANGED
@@ -45,6 +45,7 @@ module Neo4j
|
|
45
45
|
include Neo4j::ActiveNode::Dependent
|
46
46
|
include Neo4j::ActiveNode::Enum
|
47
47
|
include Neo4j::Shared::PermittedAttributes
|
48
|
+
include Neo4j::ActiveNode::DependentCallbacks
|
48
49
|
|
49
50
|
def initialize(args = nil)
|
50
51
|
self.class.ensure_id_property_info! # So that we make sure all objects have an id_property
|
@@ -26,24 +26,25 @@ module Neo4j
|
|
26
26
|
# @param [String, Symbol] other_node The identifier to use for the other end of the chain.
|
27
27
|
# @param [String, Symbol] other_rel The identifier to use for the relationship in the optional match.
|
28
28
|
# @return [Neo4j::ActiveNode::Query::QueryProxy]
|
29
|
-
def unique_nodes(association, self_identifer, other_node, other_rel)
|
29
|
+
def unique_nodes(association, self_identifer, other_node, other_rel, ids = [])
|
30
30
|
fail 'Only supported by in QueryProxy chains started by an instance' unless source_object
|
31
31
|
return false if send(association.name).empty?
|
32
|
-
unique_nodes_query(association, self_identifer, other_node, other_rel)
|
32
|
+
unique_nodes_query(association, self_identifer, other_node, other_rel, ids)
|
33
33
|
.proxy_as(association.target_class, other_node)
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
37
|
|
38
|
-
def unique_nodes_query(association, self_identifer, other_node, other_rel)
|
39
|
-
query.with(identity).proxy_as_optional(source_object.class, self_identifer)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
38
|
+
def unique_nodes_query(association, self_identifer, other_node, other_rel, ids)
|
39
|
+
base = query.with(identity).proxy_as_optional(source_object.class, self_identifer)
|
40
|
+
.send(association.name, other_node, other_rel)
|
41
|
+
base = base.where(id: ids) if ids.present?
|
42
|
+
base.query
|
43
|
+
.with(other_node)
|
44
|
+
.match("()#{association.arrow_cypher(:orphan_rel)}(#{other_node})")
|
45
|
+
.with(other_node, count: 'count(*)')
|
46
|
+
.where('count = $one', one: 1)
|
47
|
+
.break
|
47
48
|
end
|
48
49
|
end
|
49
50
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module ActiveNode
|
3
|
+
module DependentCallbacks
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def dependent_delete_callback(association, ids)
|
7
|
+
association_query_proxy(association.name).where(id: ids).delete_all
|
8
|
+
end
|
9
|
+
|
10
|
+
def dependent_delete_orphans_callback(association, ids)
|
11
|
+
unique_query = as(:self).unique_nodes(association, :self, :n, :other_rel, ids)
|
12
|
+
unique_query.query.optional_match('(n)-[r]-()').delete(:n, :r).exec if unique_query
|
13
|
+
end
|
14
|
+
|
15
|
+
def dependent_destroy_callback(association, ids)
|
16
|
+
unique_query = association_query_proxy(association.name).where(id: ids)
|
17
|
+
unique_query.each_for_destruction(self, &:destroy) if unique_query
|
18
|
+
end
|
19
|
+
|
20
|
+
def dependent_destroy_orphans_callback(association, ids)
|
21
|
+
unique_query = as(:self).unique_nodes(association, :self, :n, :other_rel, ids)
|
22
|
+
unique_query.each_for_destruction(self, &:destroy) if unique_query
|
23
|
+
end
|
24
|
+
|
25
|
+
def callbacks_from_active_rel(active_rel, direction, other_node)
|
26
|
+
rel = active_rel_corresponding_rel(active_rel, direction, other_node.class).try(:last)
|
27
|
+
public_send("dependent_#{rel.dependent}_callback", rel, [other_node.id]) if rel && rel.dependent
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -229,10 +229,9 @@ module Neo4j::ActiveNode
|
|
229
229
|
end
|
230
230
|
end
|
231
231
|
|
232
|
-
def
|
233
|
-
return unless Neo4j::Config[:enforce_has_one]
|
232
|
+
def delete_reverse_has_one_core_rel(association)
|
234
233
|
reverse_assoc = reverse_association(association)
|
235
|
-
|
234
|
+
delete_has_one_rel!(reverse_assoc) if reverse_assoc && reverse_assoc.type == :has_one
|
236
235
|
end
|
237
236
|
|
238
237
|
def reverse_association(association)
|
@@ -242,14 +241,14 @@ module Neo4j::ActiveNode
|
|
242
241
|
reverse_assoc && reverse_assoc.last
|
243
242
|
end
|
244
243
|
|
245
|
-
def
|
244
|
+
def delete_reverse_has_one_active_rel(active_rel, direction, other_node)
|
246
245
|
rel = active_rel_corresponding_rel(active_rel, direction, other_node.class)
|
247
|
-
|
246
|
+
delete_has_one_rel!(rel.last) if rel && rel.last.type == :has_one
|
248
247
|
end
|
249
248
|
|
250
|
-
def
|
251
|
-
|
252
|
-
|
249
|
+
def delete_has_one_rel!(rel)
|
250
|
+
send("#{rel.name}", :n, :r, chainable: true).query.delete(:r).exec
|
251
|
+
association_proxy_cache.clear
|
253
252
|
end
|
254
253
|
|
255
254
|
def active_rel_corresponding_rel(active_rel, direction, target_class)
|
@@ -208,7 +208,7 @@ module Neo4j
|
|
208
208
|
Neo4j::ActiveBase.run_transaction do
|
209
209
|
other_nodes.each do |other_node|
|
210
210
|
if other_node.neo_id
|
211
|
-
other_node.try(:
|
211
|
+
other_node.try(:delete_reverse_has_one_core_rel, association)
|
212
212
|
else
|
213
213
|
other_node.save
|
214
214
|
end
|
@@ -49,13 +49,37 @@ module Neo4j
|
|
49
49
|
# Deletes the relationships between all nodes for the last step in the QueryProxy chain and replaces them with relationships to the given nodes.
|
50
50
|
# Executed in the database, callbacks will not be run.
|
51
51
|
def replace_with(node_or_nodes)
|
52
|
-
|
52
|
+
node_hash = idify_hash(node_or_nodes)
|
53
|
+
original_ids = self.pluck(:id)
|
54
|
+
new_nodes = add_rels(node_hash, original_ids)
|
55
|
+
delete_rels_for_nodes(original_ids - node_hash.keys)
|
56
|
+
new_nodes | node_hash.values
|
57
|
+
end
|
58
|
+
|
59
|
+
def idify_hash(args)
|
60
|
+
Array(args).reject(&:blank?).flatten.each_with_object({}).with_index do |(arg, hash), inx|
|
61
|
+
if arg.is_a?(Integer) || arg.is_a?(String)
|
62
|
+
hash[arg.to_i] = @model.find(arg)
|
63
|
+
else
|
64
|
+
key = arg.persisted? ? arg.id : "tmp_#{inx}"
|
65
|
+
hash[key] = arg
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
53
69
|
|
54
|
-
|
55
|
-
|
56
|
-
|
70
|
+
def add_rels(node_hash, original_ids)
|
71
|
+
(node_hash.keys - original_ids).map do |id|
|
72
|
+
node_hash[id] if _create_relation_or_defer(node_hash[id])
|
57
73
|
end.compact
|
58
|
-
|
74
|
+
end
|
75
|
+
|
76
|
+
def delete_rels_for_nodes(ids)
|
77
|
+
return unless ids.present?
|
78
|
+
if association.dependent
|
79
|
+
start_object.public_send("dependent_#{association.dependent}_callback", association, ids)
|
80
|
+
else
|
81
|
+
self.where(id: ids).delete_all_rels
|
82
|
+
end
|
59
83
|
end
|
60
84
|
|
61
85
|
# Returns all relationships between a node and its last link in the QueryProxy chain, destroys them in Ruby. Callbacks will be run.
|
@@ -45,17 +45,16 @@ module Neo4j::ActiveRel
|
|
45
45
|
|
46
46
|
def create_model
|
47
47
|
validate_node_classes!
|
48
|
-
|
48
|
+
delete_has_one_rel
|
49
49
|
rel = _create_rel
|
50
50
|
return self unless rel.respond_to?(:props)
|
51
51
|
init_on_load(rel, from_node, to_node, @rel_type)
|
52
52
|
true
|
53
53
|
end
|
54
54
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
from_node.validate_reverse_has_one_active_rel(self, :out, to_node) if from_node.persisted?
|
55
|
+
def delete_has_one_rel
|
56
|
+
to_node.delete_reverse_has_one_active_rel(self, :in, from_node) if to_node.persisted?
|
57
|
+
from_node.delete_reverse_has_one_active_rel(self, :out, to_node) if from_node.persisted?
|
59
58
|
end
|
60
59
|
|
61
60
|
def query_as(var)
|
@@ -58,7 +58,7 @@ module Neo4j
|
|
58
58
|
|
59
59
|
def mark_versions_as_complete(versions)
|
60
60
|
Neo4j::ActiveBase.new_query
|
61
|
-
.with('
|
61
|
+
.with('$versions AS versions').params(versions: versions).break
|
62
62
|
.unwind(version: :versions).break
|
63
63
|
.merge('(:`Neo4j::Migrations::SchemaMigration` {migration_id: version})')
|
64
64
|
.exec
|
@@ -23,12 +23,32 @@ module Neo4j
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def fetch_index_descriptions(session)
|
26
|
-
session.query('CALL db.indexes()')
|
26
|
+
result = session.query('CALL db.indexes()')
|
27
|
+
if result.columns.include?(:description)
|
28
|
+
v3_indexes(result)
|
29
|
+
else
|
30
|
+
v4_indexes(result)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def v3_indexes(result)
|
35
|
+
result.reject do |row|
|
27
36
|
# These indexes are created automagically when the corresponding constraints are created
|
28
37
|
row.type == 'node_unique_property'
|
29
38
|
end.map(&:description)
|
30
39
|
end
|
31
40
|
|
41
|
+
def v4_indexes(result)
|
42
|
+
result.reject do |row|
|
43
|
+
# These indexes are created automagically when the corresponding constraints are created
|
44
|
+
row.uniqueness == 'UNIQUE'
|
45
|
+
end.map(&method(:description))
|
46
|
+
end
|
47
|
+
|
48
|
+
def description(row)
|
49
|
+
"INDEX FOR (n:#{row.labelsOrTypes.first}) ON (#{row.properties.map{|prop| "n.#{prop}"}.join(', ')})"
|
50
|
+
end
|
51
|
+
|
32
52
|
def drop_and_create_queries(existing, specified, remove_missing)
|
33
53
|
[].tap do |queries|
|
34
54
|
if remove_missing
|
@@ -97,11 +97,13 @@ COMMENT
|
|
97
97
|
|
98
98
|
schema_data = YAML.safe_load(File.read(SCHEMA_YAML_PATH), [Symbol])
|
99
99
|
|
100
|
-
Neo4j::
|
100
|
+
Neo4j::Transaction.subscribe_to_query(&method(:puts))
|
101
101
|
|
102
102
|
Neo4j::ActiveBase.run_transaction do
|
103
103
|
Neo4j::Migrations::Schema.synchronize_schema_data(Neo4j::ActiveBase.transaction, schema_data, args[:remove_missing])
|
104
|
+
end
|
104
105
|
|
106
|
+
Neo4j::ActiveBase.run_transaction do
|
105
107
|
runner = Neo4j::Migrations::Runner.new
|
106
108
|
runner.mark_versions_as_complete(schema_data[:versions]) # Run in test mode?
|
107
109
|
end
|
data/lib/neo4j/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activegraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 10.0.0.pre.alpha.
|
4
|
+
version: 10.0.0.pre.alpha.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Ronge, Brian Underwood, Chris Grigg, Heinrich Klobuczek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-02-
|
11
|
+
date: 2020-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -259,6 +259,7 @@ files:
|
|
259
259
|
- lib/neo4j/active_node/dependent.rb
|
260
260
|
- lib/neo4j/active_node/dependent/association_methods.rb
|
261
261
|
- lib/neo4j/active_node/dependent/query_proxy_methods.rb
|
262
|
+
- lib/neo4j/active_node/dependent_callbacks.rb
|
262
263
|
- lib/neo4j/active_node/enum.rb
|
263
264
|
- lib/neo4j/active_node/has_n.rb
|
264
265
|
- lib/neo4j/active_node/has_n/association.rb
|