n4j 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/n4j/field.rb ADDED
@@ -0,0 +1,26 @@
1
+ module N4j::Field
2
+ extend ActiveSupport::Concern
3
+ included do
4
+ end
5
+ module ClassMethods
6
+ def field(name)
7
+ define_method name do
8
+ data_access(name.to_s)
9
+ end
10
+
11
+ define_method "#{name}=" do |value|
12
+ data_set(name, value)
13
+ end
14
+ end
15
+ end
16
+
17
+ def data_access(key)
18
+ data[key]
19
+ end
20
+
21
+ def data_set(key, new_value)
22
+ new_data = data.merge({key.to_s => new_value})
23
+ self.data = new_data
24
+ end
25
+
26
+ end
data/lib/n4j/node.rb ADDED
@@ -0,0 +1,91 @@
1
+ module N4j::Node
2
+
3
+ autoload :AutoRelate, 'n4j/auto_relate'
4
+
5
+ extend ActiveSupport::Concern
6
+ included do
7
+ include AutoRelate
8
+ # include N4j::Entity
9
+ end
10
+ module ClassMethods
11
+ def find(n)
12
+ find_by_node_id(n)
13
+ end
14
+
15
+ def find_by_node_id(n)
16
+ find_by_path("/node/#{n}")
17
+ end
18
+
19
+ def find_by_path(path)
20
+ path.sub!(N4j.neo4j_url_prefix,'')
21
+ result = N4j.batch([{:to => path, :method => 'GET'}])
22
+ new(result.first['body'])
23
+ end
24
+
25
+ def service_root
26
+ find_by_node_id(0)
27
+ end
28
+ end
29
+
30
+ def initialize(hsh)
31
+ super(hsh)
32
+ unless N4j.neo4j_hash?(hsh)
33
+ self.data = hsh.dup
34
+ end
35
+ end
36
+
37
+ def create_path
38
+ '/node'
39
+ end
40
+
41
+ def body_hash
42
+ data
43
+ end
44
+
45
+ def dependent
46
+ relationships
47
+ end
48
+
49
+ def connected_unsaved
50
+ new_relationships
51
+ end
52
+
53
+ def post_save
54
+ clear_new_relationships!
55
+ end
56
+
57
+ def relationships(direction = 'all_relationships', types = [], clear_cache = false)
58
+ @relationship_cache ||= {}
59
+ if persisted?
60
+ path = from_neo4j_relative[direction] + '/' + [types].flatten.join('&')
61
+ @relationship_cache.delete(path) if clear_cache
62
+ @relationship_cache[path] ||= GenericRelationship.find_by_node_path(path)
63
+ else
64
+ []
65
+ end
66
+ end
67
+
68
+ def entity_type
69
+ 'node'
70
+ end
71
+
72
+ def traverse(opts = {})
73
+ # Started this approach, stoppedto investigate Cypher
74
+ defaults = {:start => path, :instantiate_with => self.class }
75
+ N4j::Traversal.new(:start => path)
76
+ end
77
+
78
+ def cypher(opts = {})
79
+ defaults = {:start => self}
80
+ N4j::Cypher.new(defaults.merge(opts))
81
+ end
82
+
83
+ def new_relationships
84
+ @new_relationships ||= []
85
+ end
86
+
87
+ def clear_new_relationships!
88
+ @new_relationships = []
89
+ end
90
+
91
+ end
@@ -0,0 +1,22 @@
1
+ module N4j::Relationship::Populate
2
+ extend ActiveSupport::Concern
3
+ included do
4
+ end
5
+ module ClassMethods
6
+ end
7
+
8
+ def start
9
+ if super.kind_of?(String)
10
+ @start = GenericNode.find_by_path(super)
11
+ else
12
+ super
13
+ end
14
+ end
15
+ def end
16
+ if super.kind_of?(String)
17
+ @end = GenericNode.find_by_path(super)
18
+ else
19
+ super
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ module N4j::Relationship
2
+ autoload :Populate, 'n4j/populate'
3
+ extend ActiveSupport::Concern
4
+ included do
5
+ attr_writer :type
6
+
7
+ attribute :start
8
+ attribute :end
9
+ include Populate
10
+ end
11
+
12
+ module ClassMethods
13
+ end
14
+
15
+ def initialize(hsh)
16
+ if N4j.neo4j_hash?(hsh)
17
+ super(hsh)
18
+ else
19
+ opts = HashWithIndifferentAccess.new.merge(hsh)
20
+ opts.each_pair do |k,v|
21
+ send("#{k}=",v) if %w(start end data type).include?(k)
22
+ end
23
+ end
24
+ end
25
+
26
+ def entity_type
27
+ 'relationship'
28
+ end
29
+
30
+ def prerequisites
31
+ [self.start, self.end]
32
+ end
33
+
34
+ def create_path
35
+ start.from_neo4j_relative['create_relationship'] ||
36
+ "#{start.path}/relationships"
37
+ end
38
+
39
+ def body_hash
40
+ {:to => self.end.path, :data => data, :type => type}
41
+ end
42
+
43
+ def type
44
+ @type ||= self.class.model_name.i18n_key
45
+ end
46
+
47
+ end
@@ -0,0 +1,63 @@
1
+ module N4j::Entity::Representation
2
+ extend ActiveSupport::Concern
3
+ included do
4
+ include Comparable
5
+ end
6
+ module ClassMethods
7
+ end
8
+
9
+ def <=>(another_object)
10
+ if self.class.ancestors.include?(N4j::Entity)
11
+ url <=> another_object.url
12
+ else
13
+ super(another_object)
14
+ end
15
+ end
16
+
17
+ def to_key
18
+ persisted? ? [path[/\d+\Z/]] : nil
19
+ end
20
+
21
+ def url
22
+ from_neo4j['self']
23
+ end
24
+
25
+ def path
26
+ from_neo4j_relative['self'] ||
27
+ (place_in_batch ? "{#{place_in_batch}}" : nil)
28
+ end
29
+
30
+ def create_path
31
+ raise 'Override in Node/Relationship'
32
+ end
33
+
34
+ def update_path
35
+ from_neo4j_relative['properties']
36
+ end
37
+
38
+ def body_hash
39
+ raise 'Override in Node/Relationship'
40
+ end
41
+
42
+ def persist_hash(opts = {})
43
+ if needs_persist?
44
+ persisted? ? update_hash(opts) : create_hash(opts)
45
+ end
46
+ end
47
+
48
+ def create_hash(opts={})
49
+ { :to => create_path, :method => 'POST', :body => body_hash }.merge(opts)
50
+ end
51
+
52
+ def update_hash(opts={})
53
+ {:to => update_path, :method => 'PUT', :body => body_hash}.merge(opts)
54
+ end
55
+
56
+ def destroy_hash(opts={})
57
+ {:to => path, :method => 'DELETE'}.merge(opts)
58
+ end
59
+
60
+ def show_hash(opts={})
61
+ {:to => path, :method => 'GET'}.merge(opts)
62
+ end
63
+ end
@@ -0,0 +1,39 @@
1
+ module N4j::Request
2
+ extend ActiveSupport::Concern
3
+ included do
4
+ end
5
+ module ClassMethods
6
+ def neo4j_url_prefix
7
+ @neo4j_url_prefix ||= "http://localhost:#{port}/db/data"
8
+ end
9
+
10
+ def port
11
+ config = YAML.load_file("#{Rails.root}/config/n4j.yml")
12
+ config[Rails.env]['port']
13
+ end
14
+
15
+ def neo4j_hash?(hsh)
16
+ hsh && hsh['self'] && hsh['property'] && hsh['properties']
17
+ end
18
+
19
+ def batch(commands) # [{'to'=> '', 'method' => '', 'body' => '', 'id' => 0},...]
20
+ commands.flatten!
21
+ commands.each_with_index {|command, index| command[:id] ||= index }
22
+ # puts "Batch job: #{commands.inspect}"
23
+ begin
24
+ result = RestClient.post("#{neo4j_url_prefix}/batch",
25
+ commands.to_json,
26
+ :accept => :json,
27
+ :content_type => :json)
28
+ JSON.parse(result)
29
+ rescue RestClient::InternalServerError => e
30
+ message = JSON.parse(JSON.parse(e.response)['message'])['message']
31
+ exception = JSON.parse(JSON.parse(e.response)['message'])['exception']
32
+ puts "Neo4j error: #{message}" if message
33
+ puts "Neo4j excpetion: #{exception}" if exception
34
+ rescue JSON::ParserError => e
35
+ puts "JSON::ParserError ... raw result:\n #{result}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,62 @@
1
+ class N4j::Traversal
2
+ PARAMETERS = [:order, :uniqueness, :return_filter, :prune_evaluator, :relationships, :max_depth]
3
+ attr_accessor *PARAMETERS
4
+ attr_accessor :start, :return_type
5
+
6
+ def initialize(opts ={})
7
+ opts.each_pair do |k,v|
8
+ send "#{k}=", v if respond_to?("#{k}=")
9
+ end
10
+ end
11
+
12
+ def return_type
13
+ @return_type || 'node'
14
+ end
15
+
16
+ def outbound(type)
17
+ self.relationships ||= []
18
+ self.relationships << {'direction' => 'out', 'type' => type}
19
+ self
20
+ end
21
+
22
+ def inbound(type)
23
+ self.relationships ||= []
24
+ self.relationships << {'direction' => 'in', 'type' => type}
25
+ self
26
+ end
27
+
28
+ # {
29
+ # "order" : "breadth_first",
30
+ # "return_filter" : {
31
+ # "body" : "position.endNode().getProperty('name').toLowerCase().contains('t')",
32
+ # "language" : "javascript"
33
+ # },
34
+ # "prune_evaluator" : {
35
+ # "body" : "position.length() > 10",
36
+ # "language" : "javascript"
37
+ # },
38
+ # "uniqueness" : "node_global",
39
+ # "relationships" : [ {
40
+ # "direction" : "all",
41
+ # "type" : "knows"
42
+ # }, {
43
+ # "direction" : "all",
44
+ # "type" : "loves"
45
+ # } ],
46
+ # "max_depth" : 3
47
+ # }
48
+
49
+ def traversal
50
+ # {"relationships" => [{'direction' => 'in', 'type' => 'is_a' }]}
51
+ self.class::PARAMETERS.inject({}) do |sum, n|
52
+ key = :"@#{n}"
53
+ val = instance_variable_defined?(key) && instance_variable_get(key)
54
+ sum[n] = val if val
55
+ sum
56
+ end
57
+ end
58
+
59
+ def go
60
+ N4j.batch([{:to => "#{start}/traverse/#{return_type}", :method => 'POST', :body => traversal}])
61
+ end
62
+ end
@@ -0,0 +1,3 @@
1
+ module N4j
2
+ VERSION = "0.0.1"
3
+ end
data/n4j.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "n4j/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "n4j"
7
+ s.version = N4j::VERSION
8
+ s.authors = ["Sam Schenkman-Moore"]
9
+ s.email = ["samsm@samsm.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Help using Neo4j Rest server.}
12
+ s.description = %q{A little spiked out thing.}
13
+
14
+ s.rubyforge_project = "n4j"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ s.add_runtime_dependency "rest-client"
24
+ s.add_runtime_dependency "activesupport"
25
+ s.add_runtime_dependency "activemodel"
26
+ end
data/tasks/.gitkeep ADDED
File without changes
data/tasks/n4j.rake ADDED
@@ -0,0 +1,125 @@
1
+ require 'erb'
2
+
3
+ namespace :n4j do
4
+
5
+ desc "Bug du jour"
6
+ task :bug => :environment do
7
+ require 'n4j'
8
+ gn = GenericNode.new({:test => 'foo'})
9
+ gn.save
10
+ gn.data = {:test => 'bar'}
11
+ gn.save
12
+ end
13
+
14
+ desc "Clear development database."
15
+ task :clear_development do
16
+ port = YAML.parse_file('config/n4j.yml').to_ruby['development']['port']
17
+ result = `curl --request DELETE http://localhost:#{port}/cleandb/all-gone`
18
+ puts result
19
+ end
20
+
21
+ desc "Status of Neo4j servers"
22
+ task :status do
23
+ number_of_neo4j_instances = `ps aux | grep ne[o]4j | wc -l`
24
+ number_of_neo4j_instances.strip!
25
+ puts "#{number_of_neo4j_instances} total instances of Neo4j running, system wide."
26
+ unless number_of_neo4j_instances.to_i < 1
27
+ YAML.parse_file('config/n4j.yml').to_ruby.each_pair do |environment, conf|
28
+ pid = IO.read "tmp/pids/n4j_#{environment}_pid"
29
+ pid.chomp!
30
+ result = `ps p#{pid} | grep #{pid} | wc -l`
31
+ result.strip!
32
+ puts "#{result} instances running for #{environment} (pid: #{pid})."
33
+ end
34
+ end
35
+ end
36
+
37
+ desc 'Start servers'
38
+ task :start do |task_name|
39
+ YAML.parse_file('config/n4j.yml').to_ruby.each_pair do |environment, conf|
40
+ @environment = environment
41
+ @port = conf['port']
42
+ @secure_port = conf['secure_port']
43
+ @server_version = 1.6
44
+
45
+ neo4j_bin_link = `which neo4j`
46
+ neo4j_bin_link.chomp!
47
+ neo4j_bin = Pathname.new(neo4j_bin_link).realpath
48
+
49
+ libexec = Pathname.new(neo4j_bin_link).realpath.dirname.dirname
50
+
51
+ libdir = "#{libexec}/lib"
52
+ syslib = "#{libexec}/system/lib"
53
+ plugin_dir = "#{libexec}/plugins"
54
+ n4j_plugins = 'lib/n4j/neo4j_plugins'
55
+ # coordinator ???
56
+
57
+ class_path = [libdir, syslib, plugin_dir, n4j_plugins].collect {|dir| Dir.glob(dir + '/*.jar')}.flatten.join(':')
58
+
59
+ java_opts = "-server -XX:+DisableExplicitGC -Dorg.neo4j.server.properties=conf/neo4j-server.properties -Djava.util.logging.config.file=conf/logging.properties -Xms3m -Xmx64m"
60
+
61
+
62
+
63
+ neo4j_home = "tmp/n4j/#{@environment}"
64
+
65
+ FileUtils.mkdir_p neo4j_home
66
+ FileUtils.mkdir_p "#{neo4j_home}/data/log"
67
+
68
+ FileUtils.mkdir_p 'tmp/pids'
69
+ pid_file = "tmp/pids/n4j_#{@environment}_pid"
70
+
71
+ java_command = `which java`
72
+ java_command.chomp!
73
+
74
+ system "cp lib/n4j/templates/neo4j.properties tmp/n4j/#{@environment}/"
75
+ system "cp lib/n4j/templates/logging.properties tmp/n4j/#{@environment}/"
76
+
77
+ system " touch #{neo4j_home}/data/log/console.log"
78
+
79
+ neo4j_server_properties = "##### Genereated file! May be overwritten. ##### \n" +
80
+ ERB.new(IO.read("lib/n4j/templates/neo4j-server-#{@server_version}.properties")).result
81
+ neo4j_server_properties_path = "#{neo4j_home}/neo4j-server.properties"
82
+ File.open(neo4j_server_properties_path, 'w') {|f| f.write(neo4j_server_properties) }
83
+
84
+ neo4j_wrapper_conf = "##### Genereated file! May be overwritten. ##### \n" +
85
+ ERB.new(IO.read('lib/n4j/templates/neo4j-wrapper.conf')).result
86
+ neo4j_wrapper_conf_path = "#{neo4j_home}/neo4j-wrapper.conf"
87
+ File.open(neo4j_wrapper_conf_path, 'w') {|f| f.write(neo4j_wrapper_conf) }
88
+
89
+ launch_neo4j_command = "#{java_command}
90
+ -cp #{class_path}
91
+ -server
92
+ -XX:+DisableExplicitGC
93
+ -Dorg.neo4j.server.properties=#{neo4j_server_properties_path}
94
+ -Djava.util.logging.config.file=#{neo4j_home}/logging.properties
95
+ -Xms3m
96
+ -Xmx64m
97
+ -Dlog4j.configuration=file:#{neo4j_home}/log4j.properties
98
+ -Dorg.neo4j.server.properties=#{neo4j_server_properties_path}
99
+ -Djava.util.logging.config.file=#{neo4j_home}/logging.properties
100
+ -Dneo4j.home=#{neo4j_home}
101
+ -Dneo4j.instance=#{libexec} org.neo4j.server.Bootstrapper
102
+ >> #{neo4j_home}/data/log/console.log 2>&1 & echo $! > \"#{pid_file}\"
103
+ "
104
+ # puts launch_neo4j_command
105
+ system launch_neo4j_command.gsub(/\n/,' ').gsub(/\s+/, ' ')
106
+ puts "#{environment.capitalize} Neo4j launched."
107
+
108
+ end
109
+ end
110
+
111
+ desc "Stop server"
112
+ task :stop do
113
+ YAML.parse_file('config/n4j.yml').to_ruby.each_pair do |environment, conf|
114
+ pid = IO.read "tmp/pids/n4j_#{environment}_pid"
115
+ pid.chomp!
116
+ result = `ps p#{pid} | grep #{pid} | wc -l`
117
+ if result.to_i > 0
118
+ Process.kill("HUP", pid.to_i)
119
+ puts "Killed #{environment} Neo4j."
120
+ else
121
+ puts "#{environment.capitalize} Neo4j wasn't running."
122
+ end
123
+ end
124
+ end
125
+ end