neo4j_legacy 7.2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1357 -0
  3. data/CONTRIBUTORS +8 -0
  4. data/Gemfile +38 -0
  5. data/README.md +103 -0
  6. data/bin/neo4j-jars +33 -0
  7. data/bin/rake +17 -0
  8. data/config/locales/en.yml +5 -0
  9. data/config/neo4j/add_classnames.yml +1 -0
  10. data/config/neo4j/config.yml +35 -0
  11. data/lib/active_support/per_thread_registry.rb +1 -0
  12. data/lib/backports/action_controller/metal/strong_parameters.rb +672 -0
  13. data/lib/backports/active_model/forbidden_attributes_protection.rb +30 -0
  14. data/lib/backports/active_support/concern.rb +13 -0
  15. data/lib/backports/active_support/core_ext/module/attribute_accessors.rb +10 -0
  16. data/lib/backports/active_support/logger.rb +99 -0
  17. data/lib/backports/active_support/logger_silence.rb +27 -0
  18. data/lib/backports/active_support/logger_thread_safe_level.rb +32 -0
  19. data/lib/backports/active_support/per_thread_registry.rb +60 -0
  20. data/lib/backports.rb +4 -0
  21. data/lib/neo4j/active_node/callbacks.rb +8 -0
  22. data/lib/neo4j/active_node/dependent/association_methods.rb +48 -0
  23. data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +50 -0
  24. data/lib/neo4j/active_node/dependent.rb +11 -0
  25. data/lib/neo4j/active_node/enum.rb +29 -0
  26. data/lib/neo4j/active_node/has_n/association/rel_factory.rb +61 -0
  27. data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +23 -0
  28. data/lib/neo4j/active_node/has_n/association.rb +280 -0
  29. data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +108 -0
  30. data/lib/neo4j/active_node/has_n.rb +532 -0
  31. data/lib/neo4j/active_node/id_property/accessor.rb +62 -0
  32. data/lib/neo4j/active_node/id_property.rb +187 -0
  33. data/lib/neo4j/active_node/initialize.rb +21 -0
  34. data/lib/neo4j/active_node/labels/index.rb +87 -0
  35. data/lib/neo4j/active_node/labels/reloading.rb +21 -0
  36. data/lib/neo4j/active_node/labels.rb +198 -0
  37. data/lib/neo4j/active_node/node_wrapper.rb +52 -0
  38. data/lib/neo4j/active_node/orm_adapter.rb +82 -0
  39. data/lib/neo4j/active_node/persistence.rb +175 -0
  40. data/lib/neo4j/active_node/property.rb +60 -0
  41. data/lib/neo4j/active_node/query/query_proxy.rb +361 -0
  42. data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +61 -0
  43. data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +90 -0
  44. data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +19 -0
  45. data/lib/neo4j/active_node/query/query_proxy_link.rb +117 -0
  46. data/lib/neo4j/active_node/query/query_proxy_methods.rb +210 -0
  47. data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +83 -0
  48. data/lib/neo4j/active_node/query.rb +76 -0
  49. data/lib/neo4j/active_node/query_methods.rb +65 -0
  50. data/lib/neo4j/active_node/reflection.rb +86 -0
  51. data/lib/neo4j/active_node/rels.rb +11 -0
  52. data/lib/neo4j/active_node/scope.rb +146 -0
  53. data/lib/neo4j/active_node/unpersisted.rb +48 -0
  54. data/lib/neo4j/active_node/validations.rb +59 -0
  55. data/lib/neo4j/active_node.rb +105 -0
  56. data/lib/neo4j/active_rel/callbacks.rb +15 -0
  57. data/lib/neo4j/active_rel/initialize.rb +28 -0
  58. data/lib/neo4j/active_rel/persistence/query_factory.rb +95 -0
  59. data/lib/neo4j/active_rel/persistence.rb +114 -0
  60. data/lib/neo4j/active_rel/property.rb +95 -0
  61. data/lib/neo4j/active_rel/query.rb +95 -0
  62. data/lib/neo4j/active_rel/rel_wrapper.rb +22 -0
  63. data/lib/neo4j/active_rel/related_node.rb +83 -0
  64. data/lib/neo4j/active_rel/types.rb +82 -0
  65. data/lib/neo4j/active_rel/validations.rb +8 -0
  66. data/lib/neo4j/active_rel.rb +67 -0
  67. data/lib/neo4j/class_arguments.rb +39 -0
  68. data/lib/neo4j/config.rb +124 -0
  69. data/lib/neo4j/core/query.rb +22 -0
  70. data/lib/neo4j/errors.rb +28 -0
  71. data/lib/neo4j/migration.rb +127 -0
  72. data/lib/neo4j/paginated.rb +27 -0
  73. data/lib/neo4j/railtie.rb +169 -0
  74. data/lib/neo4j/schema/operation.rb +91 -0
  75. data/lib/neo4j/shared/attributes.rb +220 -0
  76. data/lib/neo4j/shared/callbacks.rb +64 -0
  77. data/lib/neo4j/shared/cypher.rb +37 -0
  78. data/lib/neo4j/shared/declared_properties.rb +204 -0
  79. data/lib/neo4j/shared/declared_property/index.rb +37 -0
  80. data/lib/neo4j/shared/declared_property.rb +118 -0
  81. data/lib/neo4j/shared/enum.rb +148 -0
  82. data/lib/neo4j/shared/filtered_hash.rb +79 -0
  83. data/lib/neo4j/shared/identity.rb +28 -0
  84. data/lib/neo4j/shared/initialize.rb +28 -0
  85. data/lib/neo4j/shared/marshal.rb +23 -0
  86. data/lib/neo4j/shared/mass_assignment.rb +58 -0
  87. data/lib/neo4j/shared/permitted_attributes.rb +28 -0
  88. data/lib/neo4j/shared/persistence.rb +231 -0
  89. data/lib/neo4j/shared/property.rb +220 -0
  90. data/lib/neo4j/shared/query_factory.rb +101 -0
  91. data/lib/neo4j/shared/rel_type_converters.rb +43 -0
  92. data/lib/neo4j/shared/serialized_properties.rb +30 -0
  93. data/lib/neo4j/shared/type_converters.rb +418 -0
  94. data/lib/neo4j/shared/typecasted_attributes.rb +98 -0
  95. data/lib/neo4j/shared/typecaster.rb +53 -0
  96. data/lib/neo4j/shared/validations.rb +48 -0
  97. data/lib/neo4j/shared.rb +51 -0
  98. data/lib/neo4j/tasks/migration.rake +24 -0
  99. data/lib/neo4j/timestamps/created.rb +9 -0
  100. data/lib/neo4j/timestamps/updated.rb +9 -0
  101. data/lib/neo4j/timestamps.rb +11 -0
  102. data/lib/neo4j/type_converters.rb +7 -0
  103. data/lib/neo4j/version.rb +3 -0
  104. data/lib/neo4j/wrapper.rb +4 -0
  105. data/lib/neo4j.rb +96 -0
  106. data/lib/rails/generators/neo4j/model/model_generator.rb +86 -0
  107. data/lib/rails/generators/neo4j/model/templates/model.erb +15 -0
  108. data/lib/rails/generators/neo4j_generator.rb +67 -0
  109. data/neo4j.gemspec +43 -0
  110. metadata +389 -0
@@ -0,0 +1,124 @@
1
+ module Neo4j
2
+ # == Keeps configuration for neo4j
3
+ #
4
+ # == Configurations keys
5
+ class Config
6
+ DEFAULT_FILE = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'neo4j', 'config.yml'))
7
+ CLASS_NAME_PROPERTY_KEY = 'class_name_property'
8
+
9
+ class << self
10
+ # In keeping with the Rails convention, this class writer lets you globally configure
11
+ # the incluse of timestamps on your nodes and rels. It defaults to false, requiring manual
12
+ # timestamp inclusion.
13
+ # @return [Boolean] the true/false value specified.
14
+
15
+ # @return [Fixnum] The location of the default configuration file.
16
+ def default_file
17
+ @default_file ||= DEFAULT_FILE
18
+ end
19
+
20
+ # Sets the location of the configuration YAML file and old deletes configurations.
21
+ # @param [String] file_path represent the path to the file.
22
+ def default_file=(file_path)
23
+ delete_all
24
+ @defaults = nil
25
+ @default_file = File.expand_path(file_path)
26
+ end
27
+
28
+ # @return [Hash] the default file loaded by yaml
29
+ def defaults
30
+ require 'yaml'
31
+ @defaults ||= ActiveSupport::HashWithIndifferentAccess.new(YAML.load_file(default_file))
32
+ end
33
+
34
+ # Reads from the default_file if configuration is not set already
35
+ # @return [Hash] the configuration
36
+ def configuration
37
+ return @configuration if @configuration
38
+
39
+ @configuration = ActiveSupport::HashWithIndifferentAccess.new
40
+ @configuration.merge!(defaults)
41
+ @configuration
42
+ end
43
+
44
+ # Yields the configuration
45
+ #
46
+ # @example
47
+ # Neo4j::Config.use do |config|
48
+ # config[:storage_path] = '/var/neo4j'
49
+ # end
50
+ #
51
+ # @return nil
52
+ # @yield config
53
+ # @yieldparam [Neo4j::Config] config - this configuration class
54
+ def use
55
+ @configuration ||= ActiveSupport::HashWithIndifferentAccess.new
56
+ yield @configuration
57
+ nil
58
+ end
59
+
60
+ # Sets the value of a config entry.
61
+ #
62
+ # @param [Symbol] key the key to set the parameter for
63
+ # @param val the value of the parameter.
64
+ def []=(key, val)
65
+ configuration[key.to_s] = val
66
+ end
67
+
68
+ # @param [Symbol] key The key of the config entry value we want
69
+ # @return the the value of a config entry
70
+ def [](key)
71
+ configuration[key.to_s]
72
+ end
73
+
74
+ # Remove the value of a config entry.
75
+ #
76
+ # @param [Symbol] key the key of the configuration entry to delete
77
+ # @return The value of the removed entry.
78
+ def delete(key)
79
+ configuration.delete(key)
80
+ end
81
+
82
+ # Remove all configuration. This can be useful for testing purpose.
83
+ #
84
+ # @return nil
85
+ def delete_all
86
+ @configuration = nil
87
+ end
88
+
89
+ # @return [Hash] The config as a hash.
90
+ def to_hash
91
+ configuration.to_hash
92
+ end
93
+
94
+ # @return [String] The config as a YAML
95
+ def to_yaml
96
+ configuration.to_yaml
97
+ end
98
+
99
+ def include_root_in_json
100
+ # we use ternary because a simple || will always evaluate true
101
+ Neo4j::Config[:include_root_in_json].nil? ? true : Neo4j::Config[:include_root_in_json]
102
+ end
103
+
104
+ def module_handling
105
+ Neo4j::Config[:module_handling] || :none
106
+ end
107
+
108
+ # @return [Class] The configured timestamps type (e.g. Integer) or the default DateTime.
109
+ def timestamp_type
110
+ Neo4j::Config[:timestamp_type] || DateTime
111
+ end
112
+
113
+ def association_model_namespace
114
+ Neo4j::Config[:association_model_namespace] || nil
115
+ end
116
+
117
+ def association_model_namespace_string
118
+ namespace = Neo4j::Config[:association_model_namespace]
119
+ return nil if namespace.nil?
120
+ "::#{namespace}"
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,22 @@
1
+ module Neo4j::Core
2
+ class Query
3
+ # Creates a Neo4j::ActiveNode::Query::QueryProxy object that builds off of a Core::Query object.
4
+ #
5
+ # @param [Class] model An ActiveNode model to be used as the start of a new QueryuProxy chain
6
+ # @param [Symbol] var The variable to be used to refer to the object from within the new QueryProxy
7
+ # @param [Boolean] optional Indicate whether the new QueryProxy will use MATCH or OPTIONAL MATCH.
8
+ # @return [Neo4j::ActiveNode::Query::QueryProxy] A QueryProxy object.
9
+ def proxy_as(model, var, optional = false)
10
+ # TODO: Discuss whether it's necessary to call `break` on the query or if this should be left to the user.
11
+ Neo4j::ActiveNode::Query::QueryProxy.new(model, nil, node: var, optional: optional, starting_query: self, chain_level: @proxy_chain_level)
12
+ end
13
+
14
+ # Calls proxy_as with `optional` set true. This doesn't offer anything different from calling `proxy_as` directly but it may be more readable.
15
+ def proxy_as_optional(model, var)
16
+ proxy_as(model, var, true)
17
+ end
18
+
19
+ # For instances where you turn a QueryProxy into a Query and then back to a QueryProxy with `#proxy_as`
20
+ attr_accessor :proxy_chain_level
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ module Neo4j
2
+ # Neo4j.rb Errors
3
+ # Generic Neo4j.rb exception class.
4
+ class Error < StandardError
5
+ end
6
+
7
+ # Raised when Neo4j.rb cannot find record by given id.
8
+ class RecordNotFound < Error
9
+ attr_reader :model, :primary_key, :id
10
+
11
+ def initialize(message = nil, model = nil, primary_key = nil, id = nil)
12
+ @primary_key = primary_key
13
+ @model = model
14
+ @id = id
15
+
16
+ super(message)
17
+ end
18
+ end
19
+
20
+ class InvalidPropertyOptionsError < Error; end
21
+
22
+ class InvalidParameterError < Error; end
23
+
24
+ class UnknownTypeConverterError < Error; end
25
+
26
+ class DangerousAttributeError < ScriptError; end
27
+ class UnknownAttributeError < NoMethodError; end
28
+ end
@@ -0,0 +1,127 @@
1
+ require 'benchmark'
2
+
3
+ module Neo4j
4
+ class Migration
5
+ def migrate
6
+ fail 'not implemented'
7
+ end
8
+
9
+ def output(string = '')
10
+ puts string unless !!ENV['silenced']
11
+ end
12
+
13
+ def print_output(string)
14
+ print string unless !!ENV['silenced']
15
+ end
16
+
17
+ def default_path
18
+ Rails.root if defined? Rails
19
+ end
20
+
21
+ def joined_path(path)
22
+ File.join(path.to_s, 'db', 'neo4j-migrate')
23
+ end
24
+
25
+ class AddIdProperty < Neo4j::Migration
26
+ attr_reader :models_filename
27
+
28
+ def initialize(path = default_path)
29
+ @models_filename = File.join(joined_path(path), 'add_id_property.yml')
30
+ end
31
+
32
+ def migrate
33
+ models = ActiveSupport::HashWithIndifferentAccess.new(YAML.load_file(models_filename))[:models]
34
+ output 'This task will add an ID Property every node in the given file.'
35
+ output 'It may take a significant amount of time, please be patient.'
36
+ models.each do |model|
37
+ output
38
+ output
39
+ output "Adding IDs to #{model}"
40
+ add_ids_to model.constantize
41
+ end
42
+ end
43
+
44
+ def setup
45
+ FileUtils.mkdir_p('db/neo4j-migrate')
46
+
47
+ return if File.file?(models_filename)
48
+
49
+ File.open(models_filename, 'w') do |file|
50
+ message = <<MESSAGE
51
+ # Provide models to which IDs should be added.
52
+ # # It will only modify nodes that do not have IDs. There is no danger of overwriting data.
53
+ # # models: [Student,Lesson,Teacher,Exam]\nmodels: []
54
+ MESSAGE
55
+ file.write(message)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def add_ids_to(model)
62
+ max_per_batch = (ENV['MAX_PER_BATCH'] || default_max_per_batch).to_i
63
+
64
+ label = model.mapped_label_name
65
+ last_time_taken = nil
66
+
67
+ until (nodes_left = idless_count(label, model.primary_key)) == 0
68
+ print_status(last_time_taken, max_per_batch, nodes_left)
69
+
70
+ count = [nodes_left, max_per_batch].min
71
+ last_time_taken = Benchmark.realtime do
72
+ max_per_batch = id_batch_set(label, model.primary_key, count.times.map { new_id_for(model) }, count)
73
+ end
74
+ end
75
+ end
76
+
77
+ def idless_count(label, id_property)
78
+ Neo4j::Session.query.match(n: label).where("NOT EXISTS(n.#{id_property})").pluck('COUNT(n) AS ids').first
79
+ end
80
+
81
+ def print_status(last_time_taken, max_per_batch, nodes_left)
82
+ time_per_node = last_time_taken / max_per_batch if last_time_taken
83
+ message = if time_per_node
84
+ eta_seconds = (nodes_left * time_per_node).round
85
+ "#{nodes_left} nodes left. Last batch: #{(time_per_node * 1000.0).round(1)}ms / node (ETA: #{eta_seconds / 60} minutes)\r"
86
+ else
87
+ "Running first batch...\r"
88
+ end
89
+
90
+ print_output message
91
+ end
92
+
93
+
94
+ def id_batch_set(label, id_property, new_ids, count)
95
+ tx = Neo4j::Transaction.new
96
+
97
+ Neo4j::Session.query("MATCH (n:`#{label}`) WHERE NOT EXISTS(n.#{id_property})
98
+ with COLLECT(n) as nodes, #{new_ids} as ids
99
+ FOREACH(i in range(0,#{count - 1})|
100
+ FOREACH(node in [nodes[i]]|
101
+ SET node.#{id_property} = ids[i]))
102
+ RETURN distinct(true)
103
+ LIMIT #{count}")
104
+
105
+ count
106
+ rescue Neo4j::Server::CypherResponse::ResponseError, Faraday::TimeoutError
107
+ new_max_per_batch = (max_per_batch * 0.8).round
108
+ output "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
109
+ new_max_per_batch
110
+ ensure
111
+ tx.close
112
+ end
113
+
114
+ def default_max_per_batch
115
+ 900
116
+ end
117
+
118
+ def new_id_for(model)
119
+ if model.id_property_info[:type][:auto]
120
+ SecureRandom.uuid
121
+ else
122
+ model.new.send(model.id_property_info[:type][:on])
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,27 @@
1
+ module Neo4j
2
+ class Paginated
3
+ include Enumerable
4
+ attr_reader :items, :total, :current_page
5
+
6
+ def initialize(items, total, current_page)
7
+ @items = items
8
+ @total = total
9
+ @current_page = current_page
10
+ end
11
+
12
+ def self.create_from(source, page, per_page, order = nil)
13
+ target = source.node_var || source.identity
14
+ partial = source.skip((page - 1) * per_page).limit(per_page)
15
+ ordered_partial, ordered_source = if order
16
+ [partial.order_by(order), source.query.with("#{target} as #{target}").pluck("COUNT(#{target})").first]
17
+ else
18
+ [partial, source.count]
19
+ end
20
+ Paginated.new(ordered_partial, ordered_source, page)
21
+ end
22
+
23
+ delegate :each, to: :items
24
+ delegate :pluck, to: :items
25
+ delegate :size, :[], to: :items
26
+ end
27
+ end
@@ -0,0 +1,169 @@
1
+ require 'active_support/notifications'
2
+ require 'rails/railtie'
3
+ # Need the action_dispatch railtie to have action_dispatch.rescue_responses initialized correctly
4
+ require 'action_dispatch/railtie'
5
+
6
+ module Neo4j
7
+ class Railtie < ::Rails::Railtie
8
+ config.neo4j = ActiveSupport::OrderedOptions.new
9
+
10
+ if defined?(ActiveSupport::Reloader)
11
+ ActiveSupport::Reloader.to_prepare do
12
+ Neo4j::ActiveNode::Labels::Reloading.reload_models!
13
+ end
14
+ elsif const_defined?(:ActionDispatch)
15
+ ActionDispatch::Reloader.to_prepare do
16
+ Neo4j::ActiveNode::Labels::Reloading.reload_models!
17
+ end
18
+ end
19
+
20
+ # Rescue responses similar to ActiveRecord.
21
+ # For rails 3.2 and 4.0
22
+ if config.action_dispatch.respond_to?(:rescue_responses)
23
+ config.action_dispatch.rescue_responses.merge!(
24
+ 'Neo4j::RecordNotFound' => :not_found,
25
+ 'Neo4j::ActiveNode::Labels::RecordNotFound' => :not_found
26
+ )
27
+ else
28
+ # For rails 3.0 and 3.1
29
+ ActionDispatch::ShowExceptions.rescue_responses['Neo4j::RecordNotFound'] = :not_found
30
+ ActionDispatch::ShowExceptions.rescue_responses['Neo4j::ActiveNode::Labels::RecordNotFound'] = :not_found
31
+ end
32
+
33
+ # Add ActiveModel translations to the I18n load_path
34
+ initializer 'i18n' do
35
+ config.i18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', '..', '..', 'config', 'locales', '*.{rb,yml}')]
36
+ end
37
+
38
+ rake_tasks do
39
+ load 'neo4j/tasks/migration.rake'
40
+ end
41
+
42
+ class << self
43
+ def java_platform?
44
+ RUBY_PLATFORM =~ /java/
45
+ end
46
+
47
+ def setup_default_session(cfg)
48
+ setup_config_defaults!(cfg)
49
+
50
+ return if !cfg.sessions.empty?
51
+
52
+ cfg.sessions << {type: cfg.session_type, path: cfg.session_path, options: cfg.session_options.merge(default: true)}
53
+ end
54
+
55
+ def setup_config_defaults!(cfg)
56
+ cfg.session_type ||= default_session_type
57
+ cfg.session_path ||= default_session_path
58
+ cfg.session_options ||= {}
59
+ cfg.sessions ||= []
60
+ end
61
+
62
+ def config_data
63
+ @config_data ||= if yaml_path
64
+ HashWithIndifferentAccess.new(YAML.load(ERB.new(yaml_path.read).result)[Rails.env])
65
+ else
66
+ {}
67
+ end
68
+ end
69
+
70
+ def yaml_path
71
+ @yaml_path ||= %w(config/neo4j.yml config/neo4j.yaml).map do |path|
72
+ Rails.root.join(path)
73
+ end.detect(&:exist?)
74
+ end
75
+
76
+ def default_session_type
77
+ type = ENV['NEO4J_TYPE'] || config_data[:type] || :server_db
78
+ type.to_sym
79
+ end
80
+
81
+ def default_session_path
82
+ ENV['NEO4J_URL'] || ENV['NEO4J_PATH'] ||
83
+ config_data[:url] || config_data[:path] ||
84
+ 'http://localhost:7474'
85
+ end
86
+
87
+ def start_embedded_session(session)
88
+ # See https://github.com/jruby/jruby/wiki/UnlimitedStrengthCrypto
89
+ security_class = java.lang.Class.for_name('javax.crypto.JceSecurity')
90
+ restricted_field = security_class.get_declared_field('isRestricted')
91
+ restricted_field.accessible = true
92
+ restricted_field.set nil, false
93
+ session.start
94
+ end
95
+
96
+ def open_neo4j_session(options, wait_for_connection = false)
97
+ type, name, default, path = options.values_at(:type, :name, :default, :path)
98
+
99
+ if !java_platform? && type == :embedded_db
100
+ fail "Tried to start embedded Neo4j db without using JRuby (got #{RUBY_PLATFORM}), please run `rvm jruby`"
101
+ end
102
+
103
+ session = wait_for_value(wait_for_connection) do
104
+ if options.key?(:name)
105
+ Neo4j::Session.open_named(type, name, default, path)
106
+ else
107
+ Neo4j::Session.open(type, path, options[:options])
108
+ end
109
+ end
110
+
111
+ start_embedded_session(session) if type == :embedded_db
112
+ end
113
+ end
114
+
115
+ def wait_for_value(wait)
116
+ session = nil
117
+ Timeout.timeout(60) do
118
+ until session
119
+ begin
120
+ if session = yield
121
+ puts
122
+ return session
123
+ end
124
+ rescue Faraday::ConnectionFailed => e
125
+ raise e if !wait
126
+
127
+ putc '.'
128
+ sleep(1)
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ def register_neo4j_cypher_logging
135
+ return if @neo4j_cypher_logging_registered
136
+
137
+ Neo4j::Core::Query.pretty_cypher = Neo4j::Config[:pretty_logged_cypher_queries]
138
+
139
+ Neo4j::Server::CypherSession.log_with do |message|
140
+ (Neo4j::Config[:logger] || Rails.logger).debug message
141
+ end
142
+
143
+ @neo4j_cypher_logging_registered = true
144
+ end
145
+
146
+ console do
147
+ Neo4j::Config[:logger] = ActiveSupport::Logger.new(STDOUT)
148
+
149
+ register_neo4j_cypher_logging
150
+ end
151
+
152
+ # Starting Neo after :load_config_initializers allows apps to
153
+ # register migrations in config/initializers
154
+ initializer 'neo4j.start', after: :load_config_initializers do |app|
155
+ cfg = app.config.neo4j
156
+ # Set Rails specific defaults
157
+ Neo4j::Railtie.setup_default_session(cfg)
158
+
159
+ cfg.sessions.each do |session_opts|
160
+ Neo4j::Railtie.open_neo4j_session(session_opts, cfg.wait_for_connection)
161
+ end
162
+ Neo4j::Config.configuration.merge!(cfg.to_hash)
163
+
164
+ Neo4j::Config[:logger] ||= Rails.logger
165
+
166
+ register_neo4j_cypher_logging
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,91 @@
1
+ module Neo4j
2
+ module Schema
3
+ class Operation
4
+ attr_reader :label_name, :property, :options
5
+
6
+ def initialize(label_name, property, options = default_options)
7
+ @label_name = label_name.to_sym
8
+ @property = property.to_sym
9
+ @options = options
10
+ end
11
+
12
+ def self.incompatible_operation_classes
13
+ []
14
+ end
15
+
16
+ def create!
17
+ drop_incompatible!
18
+ return if exist?
19
+ label_object.send(:"create_#{type}", property, options)
20
+ end
21
+
22
+ def label_object
23
+ @label_object ||= Neo4j::Label.create(label_name)
24
+ end
25
+
26
+ def incompatible_operation_classes
27
+ self.class.incompatible_operation_classes
28
+ end
29
+
30
+ def drop!
31
+ label_object.send(:"drop_#{type}", property, options)
32
+ end
33
+
34
+ def drop_incompatible!
35
+ incompatible_operation_classes.each do |clazz|
36
+ operation = clazz.new(label_name, property)
37
+ operation.drop! if operation.exist?
38
+ end
39
+ end
40
+
41
+ def exist?
42
+ fail 'Abstract class, not implemented'
43
+ end
44
+
45
+ def default_options
46
+ {}
47
+ end
48
+
49
+ def type
50
+ fail 'Abstract class, not implemented'
51
+ end
52
+ end
53
+
54
+ class ExactIndexOperation < Neo4j::Schema::Operation
55
+ def self.incompatible_operation_classes
56
+ [UniqueConstraintOperation]
57
+ end
58
+
59
+ def type
60
+ 'index'
61
+ end
62
+
63
+ def exist?
64
+ label_object.indexes[:property_keys].include?([property])
65
+ end
66
+ end
67
+
68
+ class UniqueConstraintOperation < Neo4j::Schema::Operation
69
+ def self.incompatible_operation_classes
70
+ [ExactIndexOperation]
71
+ end
72
+
73
+ def type
74
+ 'constraint'
75
+ end
76
+
77
+ def create!
78
+ return if exist?
79
+ super
80
+ end
81
+
82
+ def exist?
83
+ Neo4j::Label.constraint?(label_name, property)
84
+ end
85
+
86
+ def default_options
87
+ {type: :unique}
88
+ end
89
+ end
90
+ end
91
+ end