neo4j 7.2.3 → 8.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -46
- data/Gemfile +15 -14
- data/README.md +21 -14
- data/bin/neo4j-jars +1 -1
- data/lib/neo4j.rb +12 -1
- data/lib/neo4j/active_base.rb +68 -0
- data/lib/neo4j/active_base/session_registry.rb +12 -0
- data/lib/neo4j/active_node.rb +13 -21
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +6 -6
- data/lib/neo4j/active_node/enum.rb +3 -6
- data/lib/neo4j/active_node/has_n.rb +24 -19
- data/lib/neo4j/active_node/has_n/association.rb +6 -2
- data/lib/neo4j/active_node/has_n/association/rel_factory.rb +1 -1
- data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +1 -1
- data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +1 -1
- data/lib/neo4j/active_node/id_property.rb +52 -15
- data/lib/neo4j/active_node/labels.rb +32 -10
- data/lib/neo4j/active_node/labels/index.rb +5 -55
- data/lib/neo4j/active_node/node_list_formatter.rb +13 -0
- data/lib/neo4j/active_node/node_wrapper.rb +39 -37
- data/lib/neo4j/active_node/persistence.rb +27 -13
- data/lib/neo4j/active_node/query/query_proxy.rb +11 -9
- data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +4 -4
- data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +1 -0
- data/lib/neo4j/active_node/query/query_proxy_link.rb +13 -9
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +76 -8
- data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +1 -1
- data/lib/neo4j/active_node/query_methods.rb +3 -3
- data/lib/neo4j/active_node/scope.rb +24 -7
- data/lib/neo4j/active_rel.rb +21 -3
- data/lib/neo4j/active_rel/initialize.rb +2 -2
- data/lib/neo4j/active_rel/persistence.rb +32 -6
- data/lib/neo4j/active_rel/persistence/query_factory.rb +3 -3
- data/lib/neo4j/active_rel/property.rb +9 -9
- data/lib/neo4j/active_rel/query.rb +6 -4
- data/lib/neo4j/active_rel/rel_wrapper.rb +24 -16
- data/lib/neo4j/active_rel/related_node.rb +5 -1
- data/lib/neo4j/active_rel/types.rb +2 -2
- data/lib/neo4j/config.rb +0 -1
- data/lib/neo4j/errors.rb +3 -0
- data/lib/neo4j/migration.rb +90 -71
- data/lib/neo4j/migrations.rb +10 -0
- data/lib/neo4j/migrations/base.rb +44 -0
- data/lib/neo4j/migrations/helpers.rb +101 -0
- data/lib/neo4j/migrations/helpers/id_property.rb +75 -0
- data/lib/neo4j/migrations/helpers/relationships.rb +66 -0
- data/lib/neo4j/migrations/helpers/schema.rb +53 -0
- data/lib/neo4j/migrations/migration_file.rb +24 -0
- data/lib/neo4j/migrations/runner.rb +110 -0
- data/lib/neo4j/migrations/schema_migration.rb +9 -0
- data/lib/neo4j/model_schema.rb +100 -0
- data/lib/neo4j/railtie.rb +29 -110
- data/lib/neo4j/schema/operation.rb +24 -13
- data/lib/neo4j/session_manager.rb +137 -0
- data/lib/neo4j/shared.rb +20 -11
- data/lib/neo4j/shared/attributes.rb +10 -16
- data/lib/neo4j/shared/callbacks.rb +3 -3
- data/lib/neo4j/shared/cypher.rb +1 -1
- data/lib/neo4j/shared/declared_properties.rb +1 -1
- data/lib/neo4j/shared/declared_property.rb +1 -1
- data/lib/neo4j/shared/enum.rb +6 -18
- data/lib/neo4j/shared/identity.rb +27 -21
- data/lib/neo4j/shared/persistence.rb +26 -17
- data/lib/neo4j/shared/property.rb +5 -2
- data/lib/neo4j/shared/query_factory.rb +4 -5
- data/lib/neo4j/shared/type_converters.rb +8 -9
- data/lib/neo4j/shared/validations.rb +1 -5
- data/lib/neo4j/tasks/migration.rake +83 -2
- data/lib/neo4j/version.rb +1 -1
- data/lib/rails/generators/neo4j/migration/migration_generator.rb +14 -0
- data/lib/rails/generators/neo4j/migration/templates/migration.erb +9 -0
- data/lib/rails/generators/neo4j/model/model_generator.rb +1 -3
- data/lib/rails/generators/neo4j_generator.rb +1 -0
- data/neo4j.gemspec +3 -3
- metadata +58 -65
- data/bin/rake +0 -17
- data/lib/neo4j/shared/permitted_attributes.rb +0 -28
@@ -27,7 +27,7 @@ module Neo4j
|
|
27
27
|
query_with_target(identifier) do |target|
|
28
28
|
begin
|
29
29
|
self.query.with(target).optional_match("(#{target})-[#{target}_rel]-()").delete("#{target}, #{target}_rel").exec
|
30
|
-
rescue Neo4j::
|
30
|
+
rescue Neo4j::Core::CypherSession::CypherError # <=- Seems hacky
|
31
31
|
self.query.delete(target).exec
|
32
32
|
end
|
33
33
|
clear_source_object_cache
|
@@ -27,14 +27,14 @@ module Neo4j
|
|
27
27
|
self.query_as(:n).return("count(#{q}) AS count").first.count
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
alias size count
|
31
|
+
alias length count
|
32
32
|
|
33
33
|
def empty?
|
34
34
|
!self.all.exists?
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
alias blank? empty?
|
38
38
|
|
39
39
|
def find_in_batches(options = {})
|
40
40
|
self.query_as(:n).return(:n).find_in_batches(:n, primary_key, options) do |batch|
|
@@ -64,7 +64,7 @@ module Neo4j::ActiveNode
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def full_scopes
|
67
|
-
|
67
|
+
self.superclass.respond_to?(:scopes) ? self.superclass.scopes.merge(scopes) : scopes
|
68
68
|
end
|
69
69
|
|
70
70
|
def _call_scope_context(eval_context, query_params, proc)
|
@@ -100,13 +100,30 @@ module Neo4j::ActiveNode
|
|
100
100
|
@target = target
|
101
101
|
end
|
102
102
|
|
103
|
+
def identity
|
104
|
+
query_proxy_or_target.identity
|
105
|
+
end
|
106
|
+
|
103
107
|
Neo4j::ActiveNode::Query::QueryProxy::METHODS.each do |method|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
108
|
+
define_method(method) do |*args|
|
109
|
+
@target.all.scoping do
|
110
|
+
query_proxy_or_target.public_send(method, *args)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def method_missing(name, *params, &block)
|
116
|
+
if query_proxy_or_target.respond_to?(name)
|
117
|
+
query_proxy_or_target.public_send(name, *params, &block)
|
118
|
+
else
|
119
|
+
super
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def query_proxy_or_target
|
126
|
+
@query_proxy_or_target ||= @query_proxy || @target
|
110
127
|
end
|
111
128
|
end
|
112
129
|
|
data/lib/neo4j/active_rel.rb
CHANGED
@@ -18,14 +18,13 @@ module Neo4j
|
|
18
18
|
include Neo4j::ActiveRel::Query
|
19
19
|
include Neo4j::ActiveRel::Types
|
20
20
|
include Neo4j::Shared::Enum
|
21
|
-
include Neo4j::Shared::PermittedAttributes
|
22
21
|
|
23
22
|
class FrozenRelError < Neo4j::Error; end
|
24
23
|
|
25
24
|
def initialize(from_node = nil, to_node = nil, args = nil)
|
26
25
|
load_nodes(node_or_nil(from_node), node_or_nil(to_node))
|
27
26
|
resolved_args = hash_or_nil(from_node, args)
|
28
|
-
symbol_args =
|
27
|
+
symbol_args = resolved_args.is_a?(Hash) ? resolved_args.symbolize_keys : resolved_args
|
29
28
|
super(symbol_args)
|
30
29
|
end
|
31
30
|
|
@@ -61,7 +60,26 @@ module Neo4j
|
|
61
60
|
end
|
62
61
|
|
63
62
|
def hash_or_nil(node_or_hash, hash_or_nil)
|
64
|
-
|
63
|
+
node_or_hash.is_a?(Hash) ? node_or_hash : hash_or_nil
|
64
|
+
end
|
65
|
+
|
66
|
+
module ClassMethods
|
67
|
+
[:create, :create!].each do |meth|
|
68
|
+
define_method(meth) do |from_node_or_args = nil, to_node = nil, args = nil|
|
69
|
+
return super(from_node_or_args) if from_node_or_args.is_a?(Hash)
|
70
|
+
args_hash = args || {}
|
71
|
+
args_with_node!(:from_node, from_node_or_args, args_hash)
|
72
|
+
args_with_node!(:to_node, to_node, args_hash)
|
73
|
+
super(args_hash)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def args_with_node!(key, node, args)
|
80
|
+
args[key] = node if node.is_a?(Neo4j::ActiveNode)
|
81
|
+
args
|
82
|
+
end
|
65
83
|
end
|
66
84
|
end
|
67
85
|
end
|
@@ -19,8 +19,8 @@ module Neo4j::ActiveRel
|
|
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_id,
|
23
|
+
unwrapped_reloaded.end_node_id,
|
24
24
|
unwrapped_reloaded.rel_type)
|
25
25
|
self
|
26
26
|
end
|
@@ -40,8 +40,7 @@ module Neo4j::ActiveRel
|
|
40
40
|
# @param [Symbol, String] name of the attribute to increment
|
41
41
|
# @param [Integer, Float] amount to increment
|
42
42
|
def concurrent_increment!(attribute, by = 1)
|
43
|
-
|
44
|
-
increment_by_query! query_rel, attribute, by
|
43
|
+
increment_by_query! query_as(:n), attribute, by
|
45
44
|
end
|
46
45
|
|
47
46
|
def create_model
|
@@ -52,16 +51,35 @@ module Neo4j::ActiveRel
|
|
52
51
|
true
|
53
52
|
end
|
54
53
|
|
54
|
+
def query_as(var)
|
55
|
+
# This should query based on the nodes, not the rel neo_id, I think
|
56
|
+
# Also, picky point: Should the var be `n`?
|
57
|
+
self.class.query_as(neo_id, var)
|
58
|
+
end
|
59
|
+
|
55
60
|
module ClassMethods
|
56
61
|
# Creates a new relationship between objects
|
57
62
|
# @param [Hash] props the properties the new relationship should have
|
58
|
-
def create(
|
59
|
-
|
63
|
+
def create(props = {})
|
64
|
+
relationship_props = extract_association_attributes!(props) || {}
|
65
|
+
new(props).tap do |obj|
|
66
|
+
relationship_props.each do |prop, value|
|
67
|
+
obj.send("#{prop}=", value)
|
68
|
+
end
|
69
|
+
obj.save
|
70
|
+
end
|
60
71
|
end
|
61
72
|
|
62
73
|
# Same as #create, but raises an error if there is a problem during save.
|
63
74
|
def create!(*args)
|
64
|
-
|
75
|
+
props = args[0] || {}
|
76
|
+
relationship_props = extract_association_attributes!(props) || {}
|
77
|
+
new(props).tap do |obj|
|
78
|
+
relationship_props.each do |prop, value|
|
79
|
+
obj.send("#{prop}=", value)
|
80
|
+
end
|
81
|
+
obj.save!
|
82
|
+
end
|
65
83
|
end
|
66
84
|
|
67
85
|
def create_method
|
@@ -69,7 +87,11 @@ module Neo4j::ActiveRel
|
|
69
87
|
end
|
70
88
|
|
71
89
|
def load_entity(id)
|
72
|
-
|
90
|
+
query_as(id).pluck(:r).first
|
91
|
+
end
|
92
|
+
|
93
|
+
def query_as(neo_id, var = :r)
|
94
|
+
Neo4j::ActiveBase.new_query.match("()-[#{var}]-()").where(var => {neo_id: neo_id})
|
73
95
|
end
|
74
96
|
end
|
75
97
|
|
@@ -79,6 +101,10 @@ module Neo4j::ActiveRel
|
|
79
101
|
|
80
102
|
private
|
81
103
|
|
104
|
+
def destroy_query
|
105
|
+
query_as(:r).delete(:r)
|
106
|
+
end
|
107
|
+
|
82
108
|
def validate_node_classes!
|
83
109
|
[from_node, to_node].each do |node|
|
84
110
|
type = from_node == node ? :_from_class : :_to_class
|
@@ -15,9 +15,9 @@ module Neo4j::ActiveRel::Persistence
|
|
15
15
|
# TODO: This feels like it should also wrap the rel, but that is handled in Neo4j::ActiveRel::Persistence at the moment.
|
16
16
|
# Builds and executes the query using the objects giving during init.
|
17
17
|
# It holds the process:
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
18
|
+
# * Execute node callbacks if needed
|
19
|
+
# * Create and execute the query
|
20
|
+
# * Mix the query response into the unpersisted objects given during init
|
21
21
|
def build!
|
22
22
|
node_before_callbacks! do
|
23
23
|
res = query_factory(rel, rel_id, iterative_query).query.unwrapped.return(*unpersisted_return_ids).first
|
@@ -6,27 +6,27 @@ module Neo4j::ActiveRel
|
|
6
6
|
include Neo4j::Shared::Property
|
7
7
|
|
8
8
|
%w(to_node from_node).each do |direction|
|
9
|
-
define_method(
|
9
|
+
define_method(direction.to_s) { instance_variable_get("@#{direction}") }
|
10
10
|
define_method("#{direction}=") do |argument|
|
11
11
|
fail FrozenRelError, 'Relationship start/end nodes cannot be changed once persisted' if _persisted_obj
|
12
12
|
instance_variable_set("@#{direction}", argument)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
alias start_node from_node
|
17
|
+
alias end_node to_node
|
18
18
|
|
19
19
|
%w(start_node end_node).each do |direction|
|
20
20
|
define_method("#{direction}_neo_id") { send(direction).neo_id if direction }
|
21
21
|
end
|
22
|
-
|
23
|
-
|
22
|
+
alias from_node_neo_id start_node_neo_id
|
23
|
+
alias to_node_neo_id end_node_neo_id
|
24
24
|
|
25
25
|
# @return [String] a string representing the relationship type that will be created
|
26
26
|
def type
|
27
27
|
self.class.type
|
28
28
|
end
|
29
|
-
|
29
|
+
alias rel_type type
|
30
30
|
|
31
31
|
def initialize(attributes = nil)
|
32
32
|
super(attributes)
|
@@ -55,7 +55,7 @@ module Neo4j::ActiveRel
|
|
55
55
|
end
|
56
56
|
|
57
57
|
%w(to_class from_class).each do |direction|
|
58
|
-
define_method(
|
58
|
+
define_method(direction.to_s) do |argument = nil|
|
59
59
|
if !argument.nil?
|
60
60
|
Neo4j::ClassArguments.validate_argument!(argument, direction)
|
61
61
|
|
@@ -73,8 +73,8 @@ module Neo4j::ActiveRel
|
|
73
73
|
(class_argument.is_a?(Array) && class_argument.all? { |c| [String, Symbol].include?(c.class) })
|
74
74
|
end
|
75
75
|
|
76
|
-
|
77
|
-
|
76
|
+
alias start_class from_class
|
77
|
+
alias end_class to_class
|
78
78
|
|
79
79
|
def load_entity(id)
|
80
80
|
Neo4j::Node.load(id)
|
@@ -12,8 +12,10 @@ module Neo4j::ActiveRel
|
|
12
12
|
end
|
13
13
|
|
14
14
|
# Loads the relationship using its neo_id.
|
15
|
-
def find_by_id(key, session =
|
16
|
-
session
|
15
|
+
def find_by_id(key, session = nil)
|
16
|
+
options = session ? {session: session} : {}
|
17
|
+
query ||= Neo4j::ActiveBase.new_query(options)
|
18
|
+
query.match('()-[r]-()').where('ID(r)' => key.to_i).limit(1).return(:r).first.r
|
17
19
|
end
|
18
20
|
|
19
21
|
# Performs a very basic match on the relationship.
|
@@ -47,12 +49,12 @@ module Neo4j::ActiveRel
|
|
47
49
|
|
48
50
|
def where_query
|
49
51
|
deprecation_warning!
|
50
|
-
Neo4j::
|
52
|
+
Neo4j::ActiveBase.new_query.match("#{cypher_string(:outbound)}-[r1:`#{self._type}`]->#{cypher_string(:inbound)}")
|
51
53
|
end
|
52
54
|
|
53
55
|
def all_query
|
54
56
|
deprecation_warning!
|
55
|
-
Neo4j::
|
57
|
+
Neo4j::ActiveBase.new_query.match("#{cypher_string}-[r1:`#{self._type}`]->#{cypher_string(:inbound)}")
|
56
58
|
end
|
57
59
|
|
58
60
|
def cypher_string(dir = :outbound)
|
@@ -1,22 +1,30 @@
|
|
1
|
-
|
2
|
-
module Wrapper
|
3
|
-
def wrapper
|
4
|
-
props.symbolize_keys!
|
5
|
-
begin
|
6
|
-
most_concrete_class = class_from_type
|
7
|
-
wrapped_rel = most_concrete_class.constantize.new
|
8
|
-
rescue NameError
|
9
|
-
return self
|
10
|
-
end
|
1
|
+
require 'neo4j/core/relationship'
|
11
2
|
|
12
|
-
|
13
|
-
|
14
|
-
|
3
|
+
wrapping_proc = proc do |relationship|
|
4
|
+
Neo4j::RelWrapping.wrapper(relationship)
|
5
|
+
end
|
6
|
+
Neo4j::Core::Relationship.wrapper_callback(wrapping_proc)
|
15
7
|
|
16
|
-
|
8
|
+
module Neo4j
|
9
|
+
module RelWrapping
|
10
|
+
class << self
|
11
|
+
def wrapper(rel)
|
12
|
+
rel.props.symbolize_keys!
|
13
|
+
begin
|
14
|
+
most_concrete_class = class_from_type(rel.rel_type)
|
15
|
+
most_concrete_class.constantize.new
|
16
|
+
rescue NameError => e
|
17
|
+
raise e unless e.message =~ /(uninitialized|wrong) constant/
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
return rel
|
20
|
+
end.tap do |wrapped_rel|
|
21
|
+
wrapped_rel.init_on_load(rel, rel.start_node_id, rel.end_node_id, rel.type)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def class_from_type(rel_type)
|
26
|
+
Neo4j::ActiveRel::Types::WRAPPED_CLASSES[rel_type] || Neo4j::ActiveRel::Types::WRAPPED_CLASSES[rel_type] = rel_type.to_s.camelize
|
27
|
+
end
|
20
28
|
end
|
21
29
|
end
|
22
30
|
end
|
@@ -29,7 +29,11 @@ module Neo4j::ActiveRel
|
|
29
29
|
# Loads a node from the database or returns the node if already laoded
|
30
30
|
def loaded
|
31
31
|
fail UnsetRelatedNodeError, 'Node not set, cannot load' if @node.nil?
|
32
|
-
@node = @node.respond_to?(:neo_id)
|
32
|
+
@node = if @node.respond_to?(:neo_id)
|
33
|
+
@node
|
34
|
+
else
|
35
|
+
Neo4j::ActiveBase.new_query.match(:n).where(n: {neo_id: @node}).pluck(:n).first
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
# @param [String, Symbol, Array] clazz An alternate label to use in the event the node is not present or loaded
|
@@ -42,8 +42,8 @@ module Neo4j
|
|
42
42
|
assign_type!(namespaced_model_name, true)
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
46
|
-
|
45
|
+
alias rel_type type
|
46
|
+
alias _type type # should be deprecated
|
47
47
|
|
48
48
|
def namespaced_model_name
|
49
49
|
case Neo4j::Config[:module_handling]
|
data/lib/neo4j/config.rb
CHANGED
@@ -4,7 +4,6 @@ module Neo4j
|
|
4
4
|
# == Configurations keys
|
5
5
|
class Config
|
6
6
|
DEFAULT_FILE = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'neo4j', 'config.yml'))
|
7
|
-
CLASS_NAME_PROPERTY_KEY = 'class_name_property'
|
8
7
|
|
9
8
|
class << self
|
10
9
|
# In keeping with the Rails convention, this class writer lets you globally configure
|
data/lib/neo4j/errors.rb
CHANGED
@@ -25,4 +25,7 @@ module Neo4j
|
|
25
25
|
|
26
26
|
class DangerousAttributeError < ScriptError; end
|
27
27
|
class UnknownAttributeError < NoMethodError; end
|
28
|
+
class MigrationError < Error; end
|
29
|
+
class IrreversibleMigration < MigrationError; end
|
30
|
+
class UnknownMigrationVersionError < MigrationError; end
|
28
31
|
end
|
data/lib/neo4j/migration.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'benchmark'
|
2
|
+
require 'neo4j/migrations/helpers/id_property'
|
2
3
|
|
3
4
|
module Neo4j
|
4
5
|
class Migration
|
@@ -7,11 +8,11 @@ module Neo4j
|
|
7
8
|
end
|
8
9
|
|
9
10
|
def output(string = '')
|
10
|
-
puts string unless !!ENV['
|
11
|
+
puts string unless !!ENV['MIGRATIONS_SILENCED']
|
11
12
|
end
|
12
13
|
|
13
14
|
def print_output(string)
|
14
|
-
print string unless !!ENV['
|
15
|
+
print string unless !!ENV['MIGRATIONS_SILENCED']
|
15
16
|
end
|
16
17
|
|
17
18
|
def default_path
|
@@ -22,7 +23,15 @@ module Neo4j
|
|
22
23
|
File.join(path.to_s, 'db', 'neo4j-migrate')
|
23
24
|
end
|
24
25
|
|
26
|
+
def setup
|
27
|
+
FileUtils.mkdir_p('db/neo4j-migrate')
|
28
|
+
end
|
29
|
+
|
30
|
+
delegate :query, to: Neo4j::Session
|
31
|
+
|
25
32
|
class AddIdProperty < Neo4j::Migration
|
33
|
+
include Neo4j::Migrations::Helpers::IdProperty
|
34
|
+
|
26
35
|
attr_reader :models_filename
|
27
36
|
|
28
37
|
def initialize(path = default_path)
|
@@ -30,6 +39,8 @@ module Neo4j
|
|
30
39
|
end
|
31
40
|
|
32
41
|
def migrate
|
42
|
+
ActiveSupport::Deprecation.warn '`AddIdProperty` task is deprecated and may be removed from future releases. '\
|
43
|
+
'Create a new migration and use the `populate_id_property` helper.', caller
|
33
44
|
models = ActiveSupport::HashWithIndifferentAccess.new(YAML.load_file(models_filename))[:models]
|
34
45
|
output 'This task will add an ID Property every node in the given file.'
|
35
46
|
output 'It may take a significant amount of time, please be patient.'
|
@@ -37,13 +48,20 @@ module Neo4j
|
|
37
48
|
output
|
38
49
|
output
|
39
50
|
output "Adding IDs to #{model}"
|
40
|
-
|
51
|
+
populate_id_property model
|
41
52
|
end
|
42
53
|
end
|
43
54
|
|
44
|
-
def
|
45
|
-
|
55
|
+
def query(*args)
|
56
|
+
ActiveBase.magic_query(*args)
|
57
|
+
end
|
58
|
+
|
59
|
+
def execute(*args)
|
60
|
+
ActiveBase.query(*args)
|
61
|
+
end
|
46
62
|
|
63
|
+
def setup
|
64
|
+
super
|
47
65
|
return if File.file?(models_filename)
|
48
66
|
|
49
67
|
File.open(models_filename, 'w') do |file|
|
@@ -56,72 +74,73 @@ MESSAGE
|
|
56
74
|
end
|
57
75
|
end
|
58
76
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
end
|
77
|
+
# Might need some of this...
|
78
|
+
# private
|
79
|
+
|
80
|
+
# def add_ids_to(model)
|
81
|
+
# max_per_batch = (ENV['MAX_PER_BATCH'] || default_max_per_batch).to_i
|
82
|
+
|
83
|
+
# label = model.mapped_label_name
|
84
|
+
# last_time_taken = nil
|
85
|
+
|
86
|
+
# until (nodes_left = idless_count(label, model.primary_key)) == 0
|
87
|
+
# print_status(last_time_taken, max_per_batch, nodes_left)
|
88
|
+
|
89
|
+
# count = [nodes_left, max_per_batch].min
|
90
|
+
# last_time_taken = Benchmark.realtime do
|
91
|
+
# max_per_batch = id_batch_set(label, model.primary_key, Array.new(count) { new_id_for(model) }, count)
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
# end
|
95
|
+
|
96
|
+
# def idless_count(label, id_property)
|
97
|
+
# Neo4j::ActiveBase.new_query.match(n: label).where("NOT EXISTS(n.#{id_property})").pluck('COUNT(n) AS ids').first
|
98
|
+
# end
|
99
|
+
|
100
|
+
# def print_status(last_time_taken, max_per_batch, nodes_left)
|
101
|
+
# time_per_node = last_time_taken / max_per_batch if last_time_taken
|
102
|
+
# message = if time_per_node
|
103
|
+
# eta_seconds = (nodes_left * time_per_node).round
|
104
|
+
# "#{nodes_left} nodes left. Last batch: #{(time_per_node * 1000.0).round(1)}ms / node (ETA: #{eta_seconds / 60} minutes)\r"
|
105
|
+
# else
|
106
|
+
# "Running first batch...\r"
|
107
|
+
# end
|
108
|
+
|
109
|
+
# print_output message
|
110
|
+
# end
|
111
|
+
|
112
|
+
|
113
|
+
# def id_batch_set(label, id_property, new_ids, count)
|
114
|
+
# tx = Neo4j::ActiveBase.new_transaction
|
115
|
+
|
116
|
+
# Neo4j::ActiveBase.current_session.query("MATCH (n:`#{label}`) WHERE NOT EXISTS(n.#{id_property})
|
117
|
+
# with COLLECT(n) as nodes, #{new_ids} as ids
|
118
|
+
# FOREACH(i in range(0,#{count - 1})|
|
119
|
+
# FOREACH(node in [nodes[i]]|
|
120
|
+
# SET node.#{id_property} = ids[i]))
|
121
|
+
# RETURN distinct(true)
|
122
|
+
# LIMIT #{count}")
|
123
|
+
|
124
|
+
# count
|
125
|
+
# rescue Neo4j::Server::CypherResponse::ResponseError, Faraday::TimeoutError
|
126
|
+
# new_max_per_batch = (max_per_batch * 0.8).round
|
127
|
+
# output "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
|
128
|
+
# new_max_per_batch
|
129
|
+
# ensure
|
130
|
+
# tx.close
|
131
|
+
# end
|
132
|
+
|
133
|
+
# def default_max_per_batch
|
134
|
+
# 900
|
135
|
+
# end
|
136
|
+
|
137
|
+
# def new_id_for(model)
|
138
|
+
# if model.id_property_info[:type][:auto]
|
139
|
+
# SecureRandom.uuid
|
140
|
+
# else
|
141
|
+
# model.new.send(model.id_property_info[:type][:on])
|
142
|
+
# end
|
143
|
+
# end
|
125
144
|
end
|
126
145
|
end
|
127
146
|
end
|