n4j 0.0.1

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.
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