Skip to content

Commit

Permalink
Merge 4da6b86 into 5392cf0
Browse files Browse the repository at this point in the history
  • Loading branch information
subvertallchris committed Sep 21, 2014
2 parents 5392cf0 + 4da6b86 commit 17a545f
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Expand Up @@ -3,7 +3,7 @@ source 'http://rubygems.org'
gemspec

#gem 'neo4j-core', path: '../neo4j-core'
gem 'neo4j-core', github: 'neo4jrb/neo4j-core'
gem 'neo4j-core', git: 'https://github.com/neo4jrb/neo4j-core'
#gem 'orm_adapter', :path => '../orm_adapter'

gem 'coveralls', require: false
Expand Down
3 changes: 2 additions & 1 deletion Rakefile
@@ -1,6 +1,7 @@
require 'rake'
require "bundler/gem_tasks"
require 'neo4j/tasks/neo4j_server'
load 'neo4j/tasks/neo4j_server.rake'
load 'neo4j/tasks/migration.rake'

desc "Generate YARD documentation"
task 'yard' do
Expand Down
88 changes: 88 additions & 0 deletions lib/neo4j/migration.rb
@@ -0,0 +1,88 @@
module Neo4j
class Migration
class AddIdProperty < Neo4j::Migration
attr_reader :models_filename

def initialize
@models_filename = File.join(Rails.root.join('db', 'neo4j-migrate'), 'add_id_property.yml')
end

def migrate
models = ActiveSupport::HashWithIndifferentAccess.new(YAML.load_file(models_filename))[:models]
puts "This task will add an ID Property every node in the given file."
puts "It may take a significant amount of time, please be patient."
models.each do |model|
puts
puts
puts "Adding IDs to #{model}"
add_ids_to model.constantize
end
end

def setup
FileUtils.mkdir_p("db/neo4j-migrate")
unless File.file?(models_filename)
File.open(models_filename, 'w') do |file|
file.write("# Provide models to which IDs should be added.\n# It will only modify nodes that do not have IDs. There is no danger of overwriting data.\n# models: [Student,Lesson,Teacher,Exam]\nmodels: []")
end
end
end

private

def add_ids_to(model)
require 'benchmark'

max_per_batch = (ENV['MAX_PER_BATCH'] || max_per_batch).to_i

label = model.mapped_label_name
property = model.primary_key
nodes_left = 1
last_time_taken = nil

until nodes_left == 0
nodes_left = Neo4j::Session.query.match(n: label).where("NOT has(n.#{property})").return("COUNT(n) AS ids").first.ids

time_per_node = last_time_taken / max_per_batch if last_time_taken
print "Running first batch...\r"
if time_per_node
eta_seconds = (nodes_left * time_per_node).round
print "#{nodes_left} nodes left. Last batch: #{(time_per_node * 1000.0).round(1)}ms / node (ETA: #{eta_seconds / 60} minutes)\r"
end

return if nodes_left == 0
to_set = [nodes_left, max_per_batch].min
new_ids = to_set.times.map { new_id_for(model) }

begin
last_time_taken = Benchmark.realtime do
Neo4j::Session.query("MATCH (n:`#{label}`) WHERE NOT has(n.#{property})
with COLLECT(n) as nodes, {new_ids} as ids
FOREACH(i in range(0,#{to_set - 1})|
FOREACH(node in [nodes[i]]|
SET node.#{property} = ids[i]))
RETURN distinct(true)
LIMIT #{to_set}", new_ids: new_ids)
end
rescue Neo4j::Server::CypherResponse::ResponseError, Faraday::TimeoutError
new_max_per_batch = (max_per_batch * 0.8).round
puts "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
max_per_batch = new_max_per_batch
end
end
end

def max_per_batch
900
end

def new_id_for(model)
if model.id_property_info[:type][:auto]
SecureRandom::uuid
else
model.new.send(model.id_property_info[:type][:on])
end
end
end
end
end
21 changes: 13 additions & 8 deletions lib/neo4j/railtie.rb
@@ -1,14 +1,20 @@
require 'active_support/notifications'
require 'rails/railtie'

module Neo4j
class Railtie < ::Rails::Railtie
class Railtie < ::Rails::Railtie
config.neo4j = ActiveSupport::OrderedOptions.new

# Add ActiveModel translations to the I18n load_path
initializer "i18n" do |app|
config.i18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', '..', '..', 'config', 'locales', '*.{rb,yml}')]
end

rake_tasks do
load 'neo4j/tasks/neo4j_server.rake'
load 'neo4j/tasks/migration.rake'
end

class << self
def java_platform?
RUBY_PLATFORM =~ /java/
Expand All @@ -26,7 +32,7 @@ def set_default_session(cfg)
end

if cfg.sessions.empty?
cfg.sessions << {type: cfg.session_type, path: cfg.session_path, options: cfg.session_options}
cfg.sessions << { type: cfg.session_type, path: cfg.session_path, options: cfg.session_options }
end
end

Expand All @@ -45,18 +51,17 @@ def open_neo4j_session(session_opts)
raise "Tried to start embedded Neo4j db without using JRuby (got #{RUBY_PLATFORM}), please run `rvm jruby`"
end

if (session_opts.key? :name)
session = Neo4j::Session.open_named(session_opts[:type], session_opts[:name], session_opts[:default], session_opts[:path])
else
session = Neo4j::Session.open(session_opts[:type], session_opts[:path], session_opts[:options])
end
session = if session_opts.key?(:name)
Neo4j::Session.open_named(session_opts[:type], session_opts[:name], session_opts[:default], session_opts[:path])
else
Neo4j::Session.open(session_opts[:type], session_opts[:path], session_opts[:options])
end

start_embedded_session(session) if session_opts[:type] == :embedded_db
end

end


# Starting Neo after :load_config_initializers allows apps to
# register migrations in config/initializers
initializer "neo4j.start", :after => :load_config_initializers do |app|
Expand Down
23 changes: 23 additions & 0 deletions lib/neo4j/tasks/migration.rake
@@ -0,0 +1,23 @@
require 'neo4j/migration'

namespace :neo4j do
desc "Run a script against the database to perform system-wide changes"
task :migrate, [:task_name, :subtask] => :environment do |_, args|
migration_task = args[:task_name]
task_name_constant = migration_task.split('_').map { |word| word.capitalize }.join('')
begin
migration_class = "Neo4j::Migration::#{task_name_constant}".constantize
rescue NameError
load File.join(Rails.root.join('db', 'neo4j-migrate'), "#{migration_task}.rb")
migration_class = "#{task_name_constant}".constantize
end
migration = migration_class.new

subtask = args[:subtask]
if subtask
migration.send(subtask)
else
migration.migrate
end
end
end

0 comments on commit 17a545f

Please sign in to comment.