activegraph 10.0.0.pre.alpha.6
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 +7 -0
- data/CHANGELOG.md +1989 -0
- data/CONTRIBUTORS +12 -0
- data/Gemfile +24 -0
- data/README.md +107 -0
- data/bin/rake +17 -0
- data/config/locales/en.yml +5 -0
- data/config/neo4j/add_classnames.yml +1 -0
- data/config/neo4j/config.yml +38 -0
- data/lib/neo4j.rb +116 -0
- data/lib/neo4j/active_base.rb +89 -0
- data/lib/neo4j/active_node.rb +108 -0
- data/lib/neo4j/active_node/callbacks.rb +8 -0
- data/lib/neo4j/active_node/dependent.rb +11 -0
- data/lib/neo4j/active_node/dependent/association_methods.rb +49 -0
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +51 -0
- data/lib/neo4j/active_node/enum.rb +26 -0
- data/lib/neo4j/active_node/has_n.rb +612 -0
- data/lib/neo4j/active_node/has_n/association.rb +278 -0
- data/lib/neo4j/active_node/has_n/association/rel_factory.rb +61 -0
- data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +23 -0
- data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +108 -0
- data/lib/neo4j/active_node/id_property.rb +224 -0
- data/lib/neo4j/active_node/id_property/accessor.rb +62 -0
- data/lib/neo4j/active_node/initialize.rb +21 -0
- data/lib/neo4j/active_node/labels.rb +207 -0
- data/lib/neo4j/active_node/labels/index.rb +37 -0
- data/lib/neo4j/active_node/labels/reloading.rb +21 -0
- data/lib/neo4j/active_node/node_list_formatter.rb +13 -0
- data/lib/neo4j/active_node/node_wrapper.rb +54 -0
- data/lib/neo4j/active_node/orm_adapter.rb +82 -0
- data/lib/neo4j/active_node/persistence.rb +187 -0
- data/lib/neo4j/active_node/property.rb +60 -0
- data/lib/neo4j/active_node/query.rb +76 -0
- data/lib/neo4j/active_node/query/query_proxy.rb +374 -0
- data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +177 -0
- data/lib/neo4j/active_node/query/query_proxy_eager_loading/association_tree.rb +75 -0
- data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +110 -0
- data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +19 -0
- data/lib/neo4j/active_node/query/query_proxy_link.rb +139 -0
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +302 -0
- data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +86 -0
- data/lib/neo4j/active_node/query_methods.rb +68 -0
- data/lib/neo4j/active_node/reflection.rb +86 -0
- data/lib/neo4j/active_node/rels.rb +11 -0
- data/lib/neo4j/active_node/scope.rb +166 -0
- data/lib/neo4j/active_node/unpersisted.rb +48 -0
- data/lib/neo4j/active_node/validations.rb +59 -0
- data/lib/neo4j/active_rel.rb +67 -0
- data/lib/neo4j/active_rel/callbacks.rb +15 -0
- data/lib/neo4j/active_rel/initialize.rb +28 -0
- data/lib/neo4j/active_rel/persistence.rb +134 -0
- data/lib/neo4j/active_rel/persistence/query_factory.rb +95 -0
- data/lib/neo4j/active_rel/property.rb +95 -0
- data/lib/neo4j/active_rel/query.rb +101 -0
- data/lib/neo4j/active_rel/rel_wrapper.rb +31 -0
- data/lib/neo4j/active_rel/related_node.rb +87 -0
- data/lib/neo4j/active_rel/types.rb +82 -0
- data/lib/neo4j/active_rel/validations.rb +8 -0
- data/lib/neo4j/ansi.rb +14 -0
- data/lib/neo4j/class_arguments.rb +39 -0
- data/lib/neo4j/config.rb +135 -0
- data/lib/neo4j/core.rb +14 -0
- data/lib/neo4j/core/connection_failed_error.rb +6 -0
- data/lib/neo4j/core/cypher_error.rb +37 -0
- data/lib/neo4j/core/driver.rb +66 -0
- data/lib/neo4j/core/has_uri.rb +63 -0
- data/lib/neo4j/core/instrumentable.rb +36 -0
- data/lib/neo4j/core/label.rb +158 -0
- data/lib/neo4j/core/logging.rb +44 -0
- data/lib/neo4j/core/node.rb +23 -0
- data/lib/neo4j/core/querable.rb +88 -0
- data/lib/neo4j/core/query.rb +487 -0
- data/lib/neo4j/core/query_builder.rb +32 -0
- data/lib/neo4j/core/query_clauses.rb +727 -0
- data/lib/neo4j/core/query_ext.rb +24 -0
- data/lib/neo4j/core/query_find_in_batches.rb +49 -0
- data/lib/neo4j/core/relationship.rb +13 -0
- data/lib/neo4j/core/responses.rb +50 -0
- data/lib/neo4j/core/result.rb +33 -0
- data/lib/neo4j/core/schema.rb +30 -0
- data/lib/neo4j/core/schema_errors.rb +12 -0
- data/lib/neo4j/core/wrappable.rb +30 -0
- data/lib/neo4j/errors.rb +57 -0
- data/lib/neo4j/migration.rb +148 -0
- data/lib/neo4j/migrations.rb +27 -0
- data/lib/neo4j/migrations/base.rb +77 -0
- data/lib/neo4j/migrations/check_pending.rb +20 -0
- data/lib/neo4j/migrations/helpers.rb +105 -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 +51 -0
- data/lib/neo4j/migrations/migration_file.rb +24 -0
- data/lib/neo4j/migrations/runner.rb +195 -0
- data/lib/neo4j/migrations/schema.rb +44 -0
- data/lib/neo4j/migrations/schema_migration.rb +14 -0
- data/lib/neo4j/model_schema.rb +139 -0
- data/lib/neo4j/paginated.rb +27 -0
- data/lib/neo4j/railtie.rb +105 -0
- data/lib/neo4j/schema/operation.rb +102 -0
- data/lib/neo4j/shared.rb +60 -0
- data/lib/neo4j/shared/attributes.rb +216 -0
- data/lib/neo4j/shared/callbacks.rb +68 -0
- data/lib/neo4j/shared/cypher.rb +37 -0
- data/lib/neo4j/shared/declared_properties.rb +204 -0
- data/lib/neo4j/shared/declared_property.rb +109 -0
- data/lib/neo4j/shared/declared_property/index.rb +37 -0
- data/lib/neo4j/shared/enum.rb +167 -0
- data/lib/neo4j/shared/filtered_hash.rb +79 -0
- data/lib/neo4j/shared/identity.rb +34 -0
- data/lib/neo4j/shared/initialize.rb +64 -0
- data/lib/neo4j/shared/marshal.rb +23 -0
- data/lib/neo4j/shared/mass_assignment.rb +64 -0
- data/lib/neo4j/shared/permitted_attributes.rb +28 -0
- data/lib/neo4j/shared/persistence.rb +282 -0
- data/lib/neo4j/shared/property.rb +240 -0
- data/lib/neo4j/shared/query_factory.rb +102 -0
- data/lib/neo4j/shared/rel_type_converters.rb +43 -0
- data/lib/neo4j/shared/serialized_properties.rb +30 -0
- data/lib/neo4j/shared/type_converters.rb +433 -0
- data/lib/neo4j/shared/typecasted_attributes.rb +98 -0
- data/lib/neo4j/shared/typecaster.rb +53 -0
- data/lib/neo4j/shared/validations.rb +44 -0
- data/lib/neo4j/tasks/migration.rake +202 -0
- data/lib/neo4j/timestamps.rb +11 -0
- data/lib/neo4j/timestamps/created.rb +9 -0
- data/lib/neo4j/timestamps/updated.rb +9 -0
- data/lib/neo4j/transaction.rb +139 -0
- data/lib/neo4j/type_converters.rb +7 -0
- data/lib/neo4j/undeclared_properties.rb +53 -0
- data/lib/neo4j/version.rb +3 -0
- data/lib/neo4j/wrapper.rb +4 -0
- 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 +88 -0
- data/lib/rails/generators/neo4j/model/templates/migration.erb +9 -0
- data/lib/rails/generators/neo4j/model/templates/model.erb +15 -0
- data/lib/rails/generators/neo4j/upgrade_v8/templates/migration.erb +17 -0
- data/lib/rails/generators/neo4j/upgrade_v8/upgrade_v8_generator.rb +32 -0
- data/lib/rails/generators/neo4j_generator.rb +119 -0
- data/neo4j.gemspec +51 -0
- metadata +421 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
|
2
|
+
require 'neo4j/core/logging'
|
|
3
|
+
require 'neo4j/core/has_uri'
|
|
4
|
+
require 'neo4j/version'
|
|
5
|
+
|
|
6
|
+
module Neo4j
|
|
7
|
+
module Core
|
|
8
|
+
class Driver
|
|
9
|
+
include HasUri
|
|
10
|
+
|
|
11
|
+
USER_AGENT_STRING = "neo4j-gem/#{::Neo4j::VERSION} (https://github.com/neo4jrb/neo4j)"
|
|
12
|
+
|
|
13
|
+
attr_accessor :wrap_level
|
|
14
|
+
attr_reader :options, :driver
|
|
15
|
+
delegate :close, to: :driver
|
|
16
|
+
|
|
17
|
+
default_url('bolt://neo4:neo4j@localhost:7687')
|
|
18
|
+
|
|
19
|
+
validate_uri do |uri|
|
|
20
|
+
uri.scheme == 'bolt'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
def new_instance(url)
|
|
25
|
+
uri = URI(url)
|
|
26
|
+
user = uri.user
|
|
27
|
+
password = uri.password
|
|
28
|
+
auth_token = if user
|
|
29
|
+
Neo4j::Driver::AuthTokens.basic(user, password)
|
|
30
|
+
else
|
|
31
|
+
Neo4j::Driver::AuthTokens.none
|
|
32
|
+
end
|
|
33
|
+
Neo4j::Driver::GraphDatabase.driver(url, auth_token)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def initialize(url, options = {})
|
|
38
|
+
self.url = url
|
|
39
|
+
@driver = self.class.new_instance(url)
|
|
40
|
+
@options = options
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def logger
|
|
44
|
+
return @logger if @logger
|
|
45
|
+
|
|
46
|
+
@logger = if @options[:logger]
|
|
47
|
+
@options[:logger]
|
|
48
|
+
else
|
|
49
|
+
Logger.new(logger_location).tap do |logger|
|
|
50
|
+
logger.level = logger_level
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def logger_location
|
|
58
|
+
@options[:logger_location] || STDOUT
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def logger_level
|
|
62
|
+
@options[:logger_level] || Logger::WARN
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Core
|
|
5
|
+
# Containing the logic for dealing with adaptors which use URIs
|
|
6
|
+
module HasUri
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
%w[scheme user password host port].each do |method|
|
|
11
|
+
define_method(method) do
|
|
12
|
+
(@uri && @uri.send(method)) || (self.class.default_uri && self.class.default_uri.send(method))
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module ClassMethods
|
|
18
|
+
attr_reader :default_uri
|
|
19
|
+
|
|
20
|
+
def default_url(default_url)
|
|
21
|
+
@default_uri = uri_from_url!(default_url)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def validate_uri(&block)
|
|
25
|
+
@uri_validator = block
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def uri_from_url!(url)
|
|
29
|
+
validate_url!(url)
|
|
30
|
+
|
|
31
|
+
@uri = url.nil? ? @default_uri : URI(url)
|
|
32
|
+
|
|
33
|
+
fail ArgumentError, "Invalid URL: #{url.inspect}" if uri_valid?(@uri)
|
|
34
|
+
|
|
35
|
+
@uri
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def validate_url!(url)
|
|
41
|
+
fail ArgumentError, "Invalid URL: #{url.inspect}" if !(url.is_a?(String) || url.nil?)
|
|
42
|
+
fail ArgumentError, 'No URL or default URL specified' if url.nil? && @default_uri.nil?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def uri_valid?(uri)
|
|
46
|
+
@uri_validator && !@uri_validator.call(uri)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def url
|
|
51
|
+
@uri.to_s
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def url=(url)
|
|
55
|
+
@uri = self.class.uri_from_url!(url)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def url_without_password
|
|
59
|
+
@url_without_password ||= "#{scheme}://#{user + ':...@' if user}#{host}:#{port}"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
require 'active_support/notifications'
|
|
3
|
+
require 'neo4j/ansi'
|
|
4
|
+
|
|
5
|
+
module Neo4j
|
|
6
|
+
module Core
|
|
7
|
+
module Instrumentable
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
EMPTY = ''
|
|
11
|
+
NEWLINE_W_SPACES = "\n "
|
|
12
|
+
|
|
13
|
+
class_methods do
|
|
14
|
+
def subscribe_to_request
|
|
15
|
+
ActiveSupport::Notifications.subscribe('neo4j.core.bolt.request') do |_, start, finish, _id, _payload|
|
|
16
|
+
ms = (finish - start) * 1000
|
|
17
|
+
yield " #{ANSI::BLUE}BOLT:#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR} #{ActiveBase.current_driver.url_without_password}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def subscribe_to_query
|
|
22
|
+
ActiveSupport::Notifications.subscribe('neo4j.core.cypher_query') do |_, _start, _finish, _id, payload|
|
|
23
|
+
query = payload[:query]
|
|
24
|
+
params_string = (query.parameters && !query.parameters.empty? ? "| #{query.parameters.inspect}" : EMPTY)
|
|
25
|
+
cypher = query.pretty_cypher ? (NEWLINE_W_SPACES if query.pretty_cypher.include?("\n")).to_s + query.pretty_cypher.gsub(/\n/, NEWLINE_W_SPACES) : query.cypher
|
|
26
|
+
|
|
27
|
+
source_line, line_number = Logging.first_external_path_and_line(caller_locations)
|
|
28
|
+
|
|
29
|
+
yield " #{ANSI::CYAN}#{query.context || 'CYPHER'}#{ANSI::CLEAR} #{cypher} #{params_string}" +
|
|
30
|
+
("\n ↳ #{source_line}:#{line_number}" if ActiveBase.current_driver.options[:verbose_query_logs] && source_line).to_s
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
module Neo4j
|
|
2
|
+
module Core
|
|
3
|
+
class Label
|
|
4
|
+
attr_reader :name
|
|
5
|
+
|
|
6
|
+
def initialize(name)
|
|
7
|
+
@name = name
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def create_index(property, options = {})
|
|
11
|
+
validate_index_options!(options)
|
|
12
|
+
properties = property.is_a?(Array) ? property.join(',') : property
|
|
13
|
+
schema_query("CREATE INDEX ON :`#{@name}`(#{properties})")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def drop_index(property, options = {})
|
|
17
|
+
validate_index_options!(options)
|
|
18
|
+
schema_query("DROP INDEX ON :`#{@name}`(#{property})")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Creates a neo4j constraint on a property
|
|
22
|
+
# See http://docs.neo4j.org/chunked/stable/query-constraints.html
|
|
23
|
+
# @example
|
|
24
|
+
# label = Neo4j::Label.create(:person, session)
|
|
25
|
+
# label.create_constraint(:name, {type: :unique}, session)
|
|
26
|
+
#
|
|
27
|
+
def create_constraint(property, constraints)
|
|
28
|
+
cypher = case constraints[:type]
|
|
29
|
+
when :unique, :uniqueness
|
|
30
|
+
"CREATE CONSTRAINT ON (n:`#{name}`) ASSERT n.`#{property}` IS UNIQUE"
|
|
31
|
+
else
|
|
32
|
+
fail "Not supported constraint #{constraints.inspect} for property #{property} (expected :type => :unique)"
|
|
33
|
+
end
|
|
34
|
+
schema_query(cypher)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def create_uniqueness_constraint(property, options = {})
|
|
38
|
+
create_constraint(property, options.merge(type: :unique))
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Drops a neo4j constraint on a property
|
|
42
|
+
# See http://docs.neo4j.org/chunked/stable/query-constraints.html
|
|
43
|
+
# @example
|
|
44
|
+
# label = Neo4j::Label.create(:person, session)
|
|
45
|
+
# label.create_constraint(:name, {type: :unique}, session)
|
|
46
|
+
# label.drop_constraint(:name, {type: :unique}, session)
|
|
47
|
+
#
|
|
48
|
+
def drop_constraint(property, constraint)
|
|
49
|
+
cypher = case constraint[:type]
|
|
50
|
+
when :unique, :uniqueness
|
|
51
|
+
"DROP CONSTRAINT ON (n:`#{name}`) ASSERT n.`#{property}` IS UNIQUE"
|
|
52
|
+
else
|
|
53
|
+
fail "Not supported constraint #{constraint.inspect}"
|
|
54
|
+
end
|
|
55
|
+
schema_query(cypher)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def drop_uniqueness_constraint(property, options = {})
|
|
59
|
+
drop_constraint(property, options.merge(type: :unique))
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def indexes
|
|
63
|
+
self.class.indexes.select do |definition|
|
|
64
|
+
definition[:label] == @name.to_sym
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.indexes
|
|
69
|
+
Neo4j::Transaction.indexes
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def drop_indexes
|
|
73
|
+
self.class.drop_indexes
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def self.drop_indexes
|
|
77
|
+
indexes.each do |definition|
|
|
78
|
+
begin
|
|
79
|
+
Neo4j::Transaction.query("DROP INDEX ON :`#{definition[:label]}`(#{definition[:properties][0]})")
|
|
80
|
+
rescue Neo4j::Server::CypherResponse::ResponseError
|
|
81
|
+
# This will error on each constraint. Ignore and continue.
|
|
82
|
+
next
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def index?(property)
|
|
88
|
+
indexes.any? { |definition| definition[:properties] == [property.to_sym] }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def constraints(_options = {})
|
|
92
|
+
Neo4j::Transaction.constraints.select do |definition|
|
|
93
|
+
definition[:label] == @name.to_sym
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def uniqueness_constraints(_options = {})
|
|
98
|
+
constraints.select do |definition|
|
|
99
|
+
definition[:type] == :uniqueness
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def drop_uniqueness_constraints
|
|
104
|
+
self.class.drop_uniqueness_constraints
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.drop_uniqueness_constraints
|
|
108
|
+
Neo4j::Transaction.constraints.each do |definition|
|
|
109
|
+
Neo4j::Transaction.query("DROP CONSTRAINT ON (n:`#{definition[:label]}`) ASSERT n.`#{definition[:properties][0]}` IS UNIQUE")
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def constraint?(property)
|
|
114
|
+
constraints.any? { |definition| definition[:properties] == [property.to_sym] }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def uniqueness_constraint?(property)
|
|
118
|
+
uniqueness_constraints.include?([property])
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def self.wait_for_schema_changes
|
|
122
|
+
schema_threads.map(&:join)
|
|
123
|
+
set_schema_threads(session, [])
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
# Store schema threads on the session so that we can easily wait for all
|
|
129
|
+
# threads on a session regardless of label
|
|
130
|
+
def schema_threads
|
|
131
|
+
self.class.schema_threads
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def schema_threads=(array)
|
|
135
|
+
self.class.set_schema_threads(array)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class << self
|
|
139
|
+
def schema_threads
|
|
140
|
+
Neo4j::Transaction.instance_variable_get('@_schema_threads') || []
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def set_schema_threads(array)
|
|
144
|
+
Neo4j::Transaction.instance_variable_set('@_schema_threads', array)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def schema_query(cypher)
|
|
149
|
+
Neo4j::Transaction.transaction { |tx| tx.query(cypher, {}) }
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def validate_index_options!(options)
|
|
153
|
+
return unless options[:type] && options[:type] != :exact
|
|
154
|
+
fail "Type #{options[:type]} is not supported"
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Copied largely from activerecord/lib/active_record/log_subscriber.rb
|
|
2
|
+
module Neo4j
|
|
3
|
+
module Core
|
|
4
|
+
module Logging
|
|
5
|
+
class << self
|
|
6
|
+
def first_external_path_and_line(callstack)
|
|
7
|
+
line = callstack.find do |frame|
|
|
8
|
+
frame.absolute_path && !ignored_callstack(frame.absolute_path)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
offending_line = line || callstack.first
|
|
12
|
+
|
|
13
|
+
[offending_line.path,
|
|
14
|
+
offending_line.lineno]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
NEO4J_CORE_GEM_ROOT = File.expand_path('../../..', __dir__) + '/'
|
|
18
|
+
|
|
19
|
+
def ignored_callstack(path)
|
|
20
|
+
paths_to_ignore.any?(&path.method(:start_with?))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def paths_to_ignore
|
|
24
|
+
@paths_to_ignore ||= [NEO4J_CORE_GEM_ROOT,
|
|
25
|
+
RbConfig::CONFIG['rubylibdir'],
|
|
26
|
+
neo4j_gem_path,
|
|
27
|
+
active_support_gem_path].compact
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def neo4j_gem_path
|
|
31
|
+
return if !defined?(::Rails.root)
|
|
32
|
+
|
|
33
|
+
@neo4j_gem_path ||= File.expand_path('../../..', Neo4j::ActiveBase.method(:current_driver).source_location[0])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def active_support_gem_path
|
|
37
|
+
return if !defined?(::ActiveSupport::Notifications)
|
|
38
|
+
|
|
39
|
+
@active_support_gem_path ||= File.expand_path('../../..', ActiveSupport::Notifications.method(:subscribe).source_location[0])
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'neo4j/core/wrappable'
|
|
2
|
+
|
|
3
|
+
module Neo4j
|
|
4
|
+
module Core
|
|
5
|
+
module Node
|
|
6
|
+
def props; properties; end
|
|
7
|
+
# Perhaps we should deprecate this?
|
|
8
|
+
def neo_id; id; end
|
|
9
|
+
|
|
10
|
+
def ==(other)
|
|
11
|
+
other.is_a?(Node) && neo_id == other.neo_id
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def labels
|
|
15
|
+
@labels ||= super
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def properties
|
|
19
|
+
@properties ||= super
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require 'neo4j/core/instrumentable'
|
|
2
|
+
require 'neo4j/transaction'
|
|
3
|
+
require 'neo4j/core/query_builder'
|
|
4
|
+
require 'neo4j/core/responses'
|
|
5
|
+
|
|
6
|
+
module Neo4j
|
|
7
|
+
module Core
|
|
8
|
+
module Querable
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
include Instrumentable
|
|
11
|
+
include Responses
|
|
12
|
+
|
|
13
|
+
class_methods do
|
|
14
|
+
def query(*args)
|
|
15
|
+
options = case args.size
|
|
16
|
+
when 3
|
|
17
|
+
args.pop
|
|
18
|
+
when 2
|
|
19
|
+
args.pop if args[0].is_a?(::Neo4j::Core::Query)
|
|
20
|
+
end || {}
|
|
21
|
+
|
|
22
|
+
queries(options) { append(*args) }[0]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def queries(options = {}, &block)
|
|
26
|
+
query_builder = QueryBuilder.new
|
|
27
|
+
|
|
28
|
+
query_builder.instance_eval(&block)
|
|
29
|
+
|
|
30
|
+
new_or_current_transaction(options[:transaction]) do |tx|
|
|
31
|
+
query_set(tx, query_builder.queries, { commit: !options[:transaction] }.merge(options))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# If called without a block, returns a Transaction object
|
|
36
|
+
# which can be used to call query/queries/mark_failed/commit
|
|
37
|
+
# If called with a block, the Transaction object is yielded
|
|
38
|
+
# to the block and `commit` is ensured. Any uncaught exceptions
|
|
39
|
+
# will mark the transaction as failed first
|
|
40
|
+
def transaction
|
|
41
|
+
return Transaction.new unless block_given?
|
|
42
|
+
|
|
43
|
+
begin
|
|
44
|
+
tx = transaction
|
|
45
|
+
|
|
46
|
+
yield tx
|
|
47
|
+
rescue => e
|
|
48
|
+
tx.mark_failed if tx
|
|
49
|
+
|
|
50
|
+
raise e
|
|
51
|
+
ensure
|
|
52
|
+
tx.close if tx
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def setup_queries!(queries, options = {})
|
|
57
|
+
return if options[:skip_instrumentation]
|
|
58
|
+
queries.each do |query|
|
|
59
|
+
ActiveSupport::Notifications.instrument('neo4j.core.cypher_query', query: query)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def query_set(transaction, queries, options = {})
|
|
64
|
+
setup_queries!(queries, skip_instrumentation: options[:skip_instrumentation])
|
|
65
|
+
|
|
66
|
+
ActiveSupport::Notifications.instrument('neo4j.core.bolt.request') do
|
|
67
|
+
self.wrap_level = options[:wrap_level]
|
|
68
|
+
queries.map do |query|
|
|
69
|
+
result_from_data(transaction.root_tx.run(query.cypher, query.parameters))
|
|
70
|
+
end
|
|
71
|
+
rescue Neo4j::Driver::Exceptions::Neo4jException => e
|
|
72
|
+
raise Neo4j::Core::CypherError.new_from(e.code, e.message) # , e.stack_track.to_a
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def new_or_current_transaction(tx, &block)
|
|
79
|
+
if tx
|
|
80
|
+
yield(tx)
|
|
81
|
+
else
|
|
82
|
+
transaction(&block)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|