Skip to content

Commit

Permalink
Merge branch 'master' of github.com:neo4jrb/neo4j
Browse files Browse the repository at this point in the history
  • Loading branch information
cheerfulstoic committed Sep 26, 2014
2 parents ef07686 + 06a2292 commit 6c14319
Show file tree
Hide file tree
Showing 17 changed files with 284 additions and 75 deletions.
1 change: 0 additions & 1 deletion example/blog/Rakefile
Expand Up @@ -2,7 +2,6 @@
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path('../config/application', __FILE__)
require 'neo4j/tasks/neo4j_server'

Blog::Application.load_tasks

2 changes: 1 addition & 1 deletion lib/neo4j/active_node.rb
Expand Up @@ -67,7 +67,7 @@ def self.inherit_id_property(other)
end

Neo4j::Session.on_session_available do |_|
id_property :uuid, auto: :uuid
id_property :uuid, auto: :uuid unless self.has_id_property?

name = Neo4j::Config[:id_property]
type = Neo4j::Config[:id_property_type]
Expand Down
6 changes: 1 addition & 5 deletions lib/neo4j/active_node/id_property.rb
Expand Up @@ -42,12 +42,8 @@ def define_id_methods(clazz, name, conf)

def validate_conf(conf)
return if conf.empty?

raise "Expected a Hash, got #{conf.class} (#{conf.to_s}) for id_property" unless conf.is_a?(Hash)

unless conf.include?(:auto) || conf.include?(:on)
raise "Illegal value #{conf.inspect} for id_property, expected :on or :auto"
end
raise "Illegal value #{conf.inspect} for id_property, expected :on or :auto" unless conf.include?(:auto) || conf.include?(:on)
end

def define_property_method(clazz, name)
Expand Down
2 changes: 1 addition & 1 deletion lib/neo4j/active_node/labels.rb
Expand Up @@ -86,7 +86,7 @@ def find_by(*args)
self.query_as(:n).where(n: eval(args.join)).limit(1).pluck(:n).first
end

# Like find_by, except that if no record is found, raises a RecordNotFound error.
# Like find_by, except that if no record is found, raises a RecordNotFound error.
def find_by!(*args)
a = eval(args.join)
find_by(args) or raise RecordNotFound, "#{self.query_as(:n).where(n: a).limit(1).to_cypher} returned no results"
Expand Down
2 changes: 1 addition & 1 deletion lib/neo4j/active_node/query/query_proxy_methods.rb
Expand Up @@ -37,7 +37,7 @@ def empty?(target=nil)
def include?(other, target=nil)
raise(InvalidParameterError, ':include? only accepts nodes') unless other.respond_to?(:neo_id)
query_with_target(target) do |target|
self.query.where(target => {@model.primary_key => other.id}).return("count(#{target}) AS count").first.count > 0
self.where("#{target}.#{other.class.primary_key} = {other_node_id}").params(other_node_id: other.id).query.return("count(#{target}) as count").first.count > 0
end
end

Expand Down
6 changes: 3 additions & 3 deletions lib/neo4j/active_node/query_methods.rb
Expand Up @@ -44,10 +44,10 @@ def include?(other)
private

def exists_query_start(node_condition)
case
when node_condition.class == Fixnum
case node_condition
when Fixnum
self.query_as(:n).where("ID(n) = #{node_condition}")
when node_condition.class == Hash
when Hash
self.where(node_condition.keys.first => node_condition.values.first)
else
self.query_as(:n)
Expand Down
2 changes: 1 addition & 1 deletion lib/neo4j/active_node/scope.rb
Expand Up @@ -61,7 +61,7 @@ def _scope

def _call_scope_context(eval_context, query_params, proc)
if proc.arity == 1
eval_context.instance_exec(query_params,&proc)
eval_context.instance_exec(query_params, &proc)
else
eval_context.instance_exec(&proc)
end
Expand Down
11 changes: 2 additions & 9 deletions lib/neo4j/active_node/validations.rb
Expand Up @@ -31,19 +31,12 @@ def validate_each(record, attribute, value)
# TODO: Added as find(:name => nil) throws error
value = "" if value == nil

if options[:case_sensitive]
conditions[attribute] = value
else
conditions[attribute] = /^#{Regexp.escape(value.to_s)}$/i
end
conditions[attribute] = options[:case_sensitive] ? value : /^#{Regexp.escape(value.to_s)}$/i

# prevent that same object is returned
# TODO: add negative condtion to not return current record
found = record.class.where(conditions).to_a.select{|f| f.neo_id != record.neo_id}

if found.count > 0
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
end
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value)) if found.count > 0
end

def message(instance)
Expand Down
20 changes: 7 additions & 13 deletions lib/neo4j/active_rel/persistence.rb
Expand Up @@ -13,9 +13,7 @@ def save(*)
end

def save!(*args)
unless save(*args)
raise RelInvalidError.new(self)
end
raise RelInvalidError.new(self) unless save(*args)
end

def create_model(*)
Expand Down Expand Up @@ -44,21 +42,17 @@ def create(props = {})

# Same as #create, but raises an error if there is a problem during save.
def create!(*args)
unless create(*args)
raise RelInvalidError.new(self)
end
raise RelInvalidError.new(self) unless create(*args)
end
end

private
private

def confirm_node_classes
[from_node, to_node].each do |node|
type = from_node == node ? :_from_class : :_to_class
next if allows_any_class?(type)
unless class_as_constant(type) == node.class
raise ModelClassInvalidError, "Node class was #{node.class}, expected #{self.class.send(type)}"
end
raise ModelClassInvalidError, "Node class was #{node.class}, expected #{self.class.send(type)}" unless class_as_constant(type) == node.class
end
end

Expand All @@ -71,10 +65,10 @@ def _create_rel(from_node, to_node, *args)

def class_as_constant(type)
given_class = self.class.send(type)
case
when given_class.is_a?(String)
case given_class
when String
given_class.constantize
when given_class.is_a?(Symbol)
when Symbol
given_class.to_s.constantize
else
given_class
Expand Down
17 changes: 8 additions & 9 deletions lib/neo4j/active_rel/query.rb
Expand Up @@ -54,7 +54,7 @@ def cypher_string(dir = :outbound)
when :inbound
identifier = '(n2'
identifier + (_to_class == :any ? ')' : cypher_label(:inbound))
end
end
end

def cypher_label(dir = :outbound)
Expand All @@ -63,22 +63,21 @@ def cypher_label(dir = :outbound)
end

def as_constant(given_class)
case
when given_class.is_a?(String)
case given_class
when String
given_class.constantize
when given_class.is_a?(Symbol)
when Symbol
given_class.to_s.constantize
else
given_class
end
end

def where_string(args)
if args.is_a?(Hash)
args.map do |k, v|
v.is_a?(Integer) ? "r1.#{k} = #{v}" : "r1.#{k} = '#{v}'"
end.join(', ')
else
case args
when Hash
args.map { |k, v| v.is_a?(Integer) ? "r1.#{k} = #{v}" : "r1.#{k} = '#{v}'" }.join(', ')
else
args
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/neo4j/active_rel/rel_wrapper.rb
Expand Up @@ -5,7 +5,7 @@ def wrapper
props.symbolize_keys!
return self unless props.is_a?(Hash) && props.has_key?(Neo4j::Config.class_name_property)
begin
found_class = props[Neo4j::Config.class_name_property].constantize
found_class = props[Neo4j::Config.class_name_property].constantize
rescue NameError
return self
end
Expand Down
55 changes: 34 additions & 21 deletions lib/neo4j/migration.rb
@@ -1,5 +1,18 @@
module Neo4j
class Migration

def migrate
raise 'not implemented'
end

def output(string = '')
puts string unless !!ENV['silenced']
end

def print_output(string)
print string unless !!ENV['silenced']
end

class AddIdProperty < Neo4j::Migration
attr_reader :models_filename

Expand All @@ -9,12 +22,12 @@ def initialize

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."
output "This task will add an ID Property every node in the given file."
output "It may take a significant amount of time, please be patient."
models.each do |model|
puts
puts
puts "Adding IDs to #{model}"
output
output
output "Adding IDs to #{model}"
add_ids_to model.constantize
end
end
Expand Down Expand Up @@ -44,10 +57,10 @@ def add_ids_to(model)
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"
print_output "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"
print_output "#{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
Expand All @@ -58,7 +71,7 @@ def add_ids_to(model)
last_time_taken = id_batch_set(label, property, new_ids, to_set)
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}"
output "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
max_per_batch = new_max_per_batch
end
end
Expand Down Expand Up @@ -92,41 +105,41 @@ def new_id_for(model)
end

class AddClassnames < Neo4j::Migration
attr_reader :classnames_filename, :classnames_filepath

def initialize
@classnames_filename = 'add_classnames.yml'
@classnames_filepath = File.join(Rails.root.join('db', 'neo4j-migrate'), classnames_filename)
end

def migrate
puts "Adding classnames. This make take some time."
output "Adding classnames. This make take some time."
execute(true)
end

def test
puts "TESTING! No queries will be executed."
output "TESTING! No queries will be executed."
execute(false)
end

def setup
puts "Creating file #{classnames_filepath}. Please use this as the migration guide."
output "Creating file #{classnames_filepath}. Please use this as the migration guide."
FileUtils.mkdir_p("db/neo4j-migrate")
unless File.file?(@classnames_filepath)
unless File.file?(classnames_filepath)
source = File.join(File.dirname(__FILE__), "..", "..", "config", "neo4j", classnames_filename)
FileUtils.copy_file(source, classnames_filepath)
end
end

private
attr_reader :classnames_filename, :classnames_filepath, :model_map

def execute(migrate = false)
file_init
map = []
map.push :nodes if @model_map[:nodes]
map.push :relationships if @model_map[:relationships]
map.push :nodes if model_map[:nodes]
map.push :relationships if model_map[:relationships]
map.each do |type|
@model_map[type].each do |action, labels|
model_map[type].each do |action, labels|
do_classnames(action, labels, type, migrate)
end
end
Expand All @@ -135,7 +148,7 @@ def execute(migrate = false)
def do_classnames(action, labels, type, migrate = false)
method = type == :nodes ? :node_cypher : :rel_cypher
labels.each do |label|
puts cypher = self.send(method, label, action)
output cypher = self.send(method, label, action)
execute_cypher(cypher) if migrate
end
end
Expand All @@ -146,7 +159,7 @@ def file_init

def node_cypher(label, action)
where, phrase_start = action_variables(action, 'n')
puts "#{phrase_start} _classname '#{label}' on nodes with matching label:"
output "#{phrase_start} _classname '#{label}' on nodes with matching label:"
"MATCH (n:`#{label}`) #{where} SET n._classname = '#{label}' RETURN COUNT(n) as modified"
end

Expand All @@ -161,13 +174,13 @@ def rel_cypher(hash, action)
to_cypher = to ? "(to:`#{to}`)" : "(to)"
type = "[r:`#{value[:type]}`]"
where, phrase_start = action_variables(action, 'r')
puts "#{phrase_start} _classname '#{label}' where type is '#{value[:type]}' using cypher:"
output "#{phrase_start} _classname '#{label}' where type is '#{value[:type]}' using cypher:"
"MATCH #{from_cypher}-#{type}->#{to_cypher} #{where} SET r._classname = '#{label}' return COUNT(r) as modified"
end

def execute_cypher(query_string)
puts "Modified #{Neo4j::Session.query(query_string).first.modified} records"
puts ""
output "Modified #{Neo4j::Session.query(query_string).first.modified} records"
output ""
end

def action_variables(action, identifier)
Expand Down
14 changes: 9 additions & 5 deletions lib/neo4j/shared/property.rb
Expand Up @@ -108,11 +108,7 @@ def instantiate_object(field, values_with_empty_parameters)
return nil if values_with_empty_parameters.all? { |v| v.nil? }
values = values_with_empty_parameters.collect { |v| v.nil? ? 1 : v }
klass = field[:type]
if klass
klass.new(*values)
else
values
end
klass ? klass.new(*values) : values
end

module ClassMethods
Expand Down Expand Up @@ -163,6 +159,7 @@ def undef_property(name)
end

def default_property(name, &block)
reset_default_properties(name) if default_properties.respond_to?(:size)
default_properties[name] = block
end

Expand All @@ -171,6 +168,13 @@ def default_properties
@default_property ||= {}
end

def reset_default_properties(name_to_keep)
default_properties.each_key do |property|
undef_method(property) unless property == name_to_keep
end
@default_property = {}
end

def default_property_values(instance)
default_properties.each_with_object({}) do |(key, block),result|
result[key] = block.call(instance)
Expand Down
8 changes: 4 additions & 4 deletions lib/neo4j/shared/validations.rb
Expand Up @@ -28,13 +28,13 @@ def valid?(context = nil)
super(context)
errors.empty?
end

private

def perform_validations(options={})
perform_validation = case options
when Hash
options[:validate] != false
when Hash
options[:validate] != false
end

if perform_validation
Expand Down

0 comments on commit 6c14319

Please sign in to comment.