neo4j_ancestry 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.
Files changed (125) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.md +5 -0
  5. data/Gemfile +7 -0
  6. data/Guardfile +24 -0
  7. data/MIT-LICENSE +22 -0
  8. data/README.md +73 -0
  9. data/Rakefile +15 -0
  10. data/config/initializers/001_neo4j.rb +39 -0
  11. data/db/migrate/20131102235736_create_links.rb +10 -0
  12. data/lib/models/neo4j_ancestry/active_record_additions.rb +111 -0
  13. data/lib/models/neo4j_ancestry/link.rb +28 -0
  14. data/lib/models/neo4j_ancestry/node_instance_methods.rb +93 -0
  15. data/lib/neo4j_ancestry.rb +11 -0
  16. data/lib/neo4j_ancestry/engine.rb +13 -0
  17. data/lib/neo4j_ancestry/railtie.rb +22 -0
  18. data/lib/neo4j_ancestry/version.rb +3 -0
  19. data/lib/tasks/db_test_prepare.rake +26 -0
  20. data/lib/tasks/setup.rake +24 -0
  21. data/lib/tasks/start.rake +12 -0
  22. data/lib/tasks/stop.rake +12 -0
  23. data/neo4j_ancestry.gemspec +33 -0
  24. data/rails3.2.Gemfile +7 -0
  25. data/rails4.Gemfile +7 -0
  26. data/script/rails +8 -0
  27. data/spec/dummy-rails3/.gitignore +15 -0
  28. data/spec/dummy-rails3/Gemfile +40 -0
  29. data/spec/dummy-rails3/README.rdoc +261 -0
  30. data/spec/dummy-rails3/Rakefile +7 -0
  31. data/spec/dummy-rails3/app/assets/images/rails.png +0 -0
  32. data/spec/dummy-rails3/app/assets/javascripts/application.js +15 -0
  33. data/spec/dummy-rails3/app/assets/stylesheets/application.css +13 -0
  34. data/spec/dummy-rails3/app/controllers/application_controller.rb +3 -0
  35. data/spec/dummy-rails3/app/helpers/application_helper.rb +2 -0
  36. data/spec/dummy-rails3/app/mailers/.gitkeep +0 -0
  37. data/spec/dummy-rails3/app/views/layouts/application.html.erb +14 -0
  38. data/spec/dummy-rails3/config.ru +4 -0
  39. data/spec/dummy-rails3/config/application.rb +62 -0
  40. data/spec/dummy-rails3/config/boot.rb +6 -0
  41. data/spec/dummy-rails3/config/database.yml +25 -0
  42. data/spec/dummy-rails3/config/environment.rb +5 -0
  43. data/spec/dummy-rails3/config/environments/development.rb +37 -0
  44. data/spec/dummy-rails3/config/environments/production.rb +67 -0
  45. data/spec/dummy-rails3/config/environments/test.rb +37 -0
  46. data/spec/dummy-rails3/config/initializers/backtrace_silencers.rb +7 -0
  47. data/spec/dummy-rails3/config/initializers/inflections.rb +15 -0
  48. data/spec/dummy-rails3/config/initializers/mime_types.rb +5 -0
  49. data/spec/dummy-rails3/config/initializers/secret_token.rb +7 -0
  50. data/spec/dummy-rails3/config/initializers/session_store.rb +8 -0
  51. data/spec/dummy-rails3/config/initializers/wrap_parameters.rb +14 -0
  52. data/spec/dummy-rails3/config/locales/en.yml +5 -0
  53. data/spec/dummy-rails3/config/routes.rb +58 -0
  54. data/spec/dummy-rails3/db/schema.rb +35 -0
  55. data/spec/dummy-rails3/db/seeds.rb +7 -0
  56. data/spec/dummy-rails3/lib/assets/.gitkeep +0 -0
  57. data/spec/dummy-rails3/lib/tasks/.gitkeep +0 -0
  58. data/spec/dummy-rails3/log/.gitkeep +0 -0
  59. data/spec/dummy-rails3/public/404.html +26 -0
  60. data/spec/dummy-rails3/public/422.html +26 -0
  61. data/spec/dummy-rails3/public/500.html +25 -0
  62. data/spec/dummy-rails3/public/favicon.ico +0 -0
  63. data/spec/dummy-rails3/public/index.html +241 -0
  64. data/spec/dummy-rails3/public/robots.txt +5 -0
  65. data/spec/dummy-rails3/rails3.2.Gemfile.lock +131 -0
  66. data/spec/dummy-rails3/script/rails +6 -0
  67. data/spec/dummy-rails3/vendor/assets/javascripts/.gitkeep +0 -0
  68. data/spec/dummy-rails3/vendor/assets/stylesheets/.gitkeep +0 -0
  69. data/spec/dummy-rails3/vendor/plugins/.gitkeep +0 -0
  70. data/spec/dummy-rails4/.gitignore +16 -0
  71. data/spec/dummy-rails4/Gemfile +47 -0
  72. data/spec/dummy-rails4/README.rdoc +28 -0
  73. data/spec/dummy-rails4/Rakefile +6 -0
  74. data/spec/dummy-rails4/app/assets/images/.keep +0 -0
  75. data/spec/dummy-rails4/app/assets/javascripts/application.js +16 -0
  76. data/spec/dummy-rails4/app/assets/stylesheets/application.css +13 -0
  77. data/spec/dummy-rails4/app/controllers/application_controller.rb +5 -0
  78. data/spec/dummy-rails4/app/controllers/concerns/.keep +0 -0
  79. data/spec/dummy-rails4/app/helpers/application_helper.rb +2 -0
  80. data/spec/dummy-rails4/app/mailers/.keep +0 -0
  81. data/spec/dummy-rails4/app/models/.keep +0 -0
  82. data/spec/dummy-rails4/app/models/concerns/.keep +0 -0
  83. data/spec/dummy-rails4/app/models/group.rb +10 -0
  84. data/spec/dummy-rails4/app/models/user.rb +3 -0
  85. data/spec/dummy-rails4/app/views/layouts/application.html.erb +14 -0
  86. data/spec/dummy-rails4/bin/bundle +3 -0
  87. data/spec/dummy-rails4/bin/rails +4 -0
  88. data/spec/dummy-rails4/bin/rake +4 -0
  89. data/spec/dummy-rails4/config.ru +4 -0
  90. data/spec/dummy-rails4/config/application.rb +23 -0
  91. data/spec/dummy-rails4/config/boot.rb +4 -0
  92. data/spec/dummy-rails4/config/database.yml +25 -0
  93. data/spec/dummy-rails4/config/environment.rb +5 -0
  94. data/spec/dummy-rails4/config/environments/development.rb +29 -0
  95. data/spec/dummy-rails4/config/environments/production.rb +80 -0
  96. data/spec/dummy-rails4/config/environments/test.rb +36 -0
  97. data/spec/dummy-rails4/config/initializers/backtrace_silencers.rb +7 -0
  98. data/spec/dummy-rails4/config/initializers/filter_parameter_logging.rb +4 -0
  99. data/spec/dummy-rails4/config/initializers/inflections.rb +16 -0
  100. data/spec/dummy-rails4/config/initializers/mime_types.rb +5 -0
  101. data/spec/dummy-rails4/config/initializers/secret_token.rb +12 -0
  102. data/spec/dummy-rails4/config/initializers/session_store.rb +3 -0
  103. data/spec/dummy-rails4/config/initializers/wrap_parameters.rb +14 -0
  104. data/spec/dummy-rails4/config/locales/en.yml +23 -0
  105. data/spec/dummy-rails4/config/routes.rb +57 -0
  106. data/spec/dummy-rails4/db/migrate/20131102131519_create_users.rb +9 -0
  107. data/spec/dummy-rails4/db/migrate/20131102131531_create_groups.rb +9 -0
  108. data/spec/dummy-rails4/db/migrate/20131103162013_create_links.neo4j_ancestry.rb +11 -0
  109. data/spec/dummy-rails4/db/schema.rb +35 -0
  110. data/spec/dummy-rails4/db/seeds.rb +7 -0
  111. data/spec/dummy-rails4/lib/assets/.keep +0 -0
  112. data/spec/dummy-rails4/lib/tasks/.keep +0 -0
  113. data/spec/dummy-rails4/log/.keep +0 -0
  114. data/spec/dummy-rails4/public/404.html +58 -0
  115. data/spec/dummy-rails4/public/422.html +58 -0
  116. data/spec/dummy-rails4/public/500.html +57 -0
  117. data/spec/dummy-rails4/public/favicon.ico +0 -0
  118. data/spec/dummy-rails4/public/robots.txt +5 -0
  119. data/spec/dummy-rails4/vendor/assets/javascripts/.keep +0 -0
  120. data/spec/dummy-rails4/vendor/assets/stylesheets/.keep +0 -0
  121. data/spec/models/neo4j_ancestry/active_record_additions_spec.rb +78 -0
  122. data/spec/models/neo4j_ancestry/link_spec.rb +12 -0
  123. data/spec/spec_helper.rb +26 -0
  124. data/spec/support/schema.rb +42 -0
  125. metadata +409 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 41f4f1d28904e2ce9f72234d37fa139a1d3145ba
4
+ data.tar.gz: 172c0d6e21aa0053312c9a2ccdbd9bd3ae205ba5
5
+ SHA512:
6
+ metadata.gz: 8ef1393a7263e2bf86610d6e7f37e8ce74c62a7c2bbcae3d3de58328346b065328bd61c5242605d1250c75115239fb23acb2dea3c53f49fa810198e9ba306f54
7
+ data.tar.gz: c30f176d2e86e34cce179ed68fa0783b6b3b62bdd79e4d2b41f24d09b26a0b33e550968d52e001ef0a284d6b7b946127ef6312301b8f2cdefa17eff30447cb5a
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ # neo4j database of the dummy app
20
+ spec/dummy-rails4/db/neo4j
21
+ spec/dummy-rails3/db/neo4j
22
+ spec/dummy-rails4/neo4j
23
+ spec/dummy-rails3/neo4j
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ gemfile:
6
+ - rails3.2.Gemfile
7
+ - rails4.Gemfile
8
+ before_script:
9
+ - bundle exec rake neo4j_ancestry:db:test:prepare
10
+ after_script:
11
+ - bundle exec rake neo4j:stop
@@ -0,0 +1,5 @@
1
+ # Neo4jAncestry Changelog
2
+
3
+ * v0.0.1 - Initial Release with basic functionality.
4
+ * Rake tasks for installation and setup of neo4j.
5
+ * Basic traversing methods, such as `parents`, `children`, `ancestors`, `descendants`, `siblings`.
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Testing for Rails 4
4
+ gem 'rails', '~> 4'
5
+
6
+ # Specify your gem's dependencies in neo4j_ancestry.gemspec
7
+ gemspec
@@ -0,0 +1,24 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec, cli: "--color" do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Sebastian Fiedlschuster
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,73 @@
1
+ # Neo4jAncestry
2
+
3
+ [![Build Status](https://travis-ci.org/fiedl/neo4j_ancestry.png?branch=master)](https://travis-ci.org/fiedl/neo4j_ancestry)
4
+
5
+ This ruby on rails gem makes it easy to store polymorphic structure information --- `parents`, `children`, `ancestors`, `descendants`, ... --- in a [neo4j graph database](http://www.neo4j.org) parallel to using ActiveRecord.
6
+
7
+ All relevant information is stored in your default ActiveRecord database, including the parent-child relationships. But, in addition, the structure information is also stored in a neo4j graph database in order to use its power of fast graph traversing queries.
8
+
9
+ ## Usage
10
+
11
+ TODO: Write usage instructions here
12
+
13
+
14
+ ## Installation
15
+
16
+ Add the gem to your application's `Gemfile`:
17
+
18
+ # Gemfile
19
+ # ...
20
+ gem 'neo4j_ancestry'
21
+
22
+ And then execute:
23
+
24
+ # bash
25
+ bundle install
26
+
27
+ Install the neo4j database `db` directory and start the deamon:
28
+
29
+ # bash
30
+ bundle exec rake neo4j:install neo4j:setup neo4j:start
31
+
32
+ Next, migrate the database in order to add the neccessary tables.
33
+
34
+ # bash
35
+ bundle exec rake neo4j_ancestry:install:migrations
36
+ bundle exec rake db:migrate
37
+
38
+
39
+ ## Underlying Technology
40
+
41
+ * The [neo4j graph database](http://www.neo4j.org)
42
+ * The [neography gem](https://github.com/maxdemarzi/neography) is used as datbase interface.
43
+ * The [neoid gem](https://github.com/elado/neoid) is used for database abstraction in parallel to ActiveRecord.
44
+
45
+ ## Contributing
46
+
47
+ 1. Fork it
48
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
49
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
50
+ 4. Push to the branch (`git push origin my-new-feature`)
51
+ 5. Create new Pull Request
52
+
53
+ ### Running the Gem's Specs Locally
54
+
55
+ Symlink the `Gemfile` according to the Rails version you would like to use:
56
+
57
+ # bash
58
+ rm Gemfile Gemfile.lock
59
+ ln -s rails3.2.Gemfile Gemfile # for Rails 3
60
+ ln -s rails4.Gemfile Gemfile # for Rails 4 (default)
61
+
62
+ Next, install the dependencies and run the specs.
63
+
64
+ # bash
65
+ bundle install
66
+ bundle exec rake neo4j_ancestry:db:test:prepare
67
+ bundle exec rake
68
+
69
+ ## Author, License
70
+
71
+ (c) 2013, Sebastian Fiedlschuster
72
+
73
+ Released under the [MIT License](./MIT-LICENSE).
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require "bundler/gem_tasks"
8
+ Bundler::GemHelper.install_tasks
9
+
10
+ load "lib/tasks/db_test_prepare.rake"
11
+
12
+ require 'rspec/core/rake_task'
13
+ RSpec::Core::RakeTask.new(:spec)
14
+
15
+ task default: :spec
@@ -0,0 +1,39 @@
1
+ # This initializers estableshes the connection to the neo4j graph database.
2
+ # The settings for this connection are stored in
3
+ #
4
+ # # TODO
5
+ #
6
+ # For further information how this connection works, have a look at:
7
+ #
8
+ # https://github.com/elado/neoid#usage
9
+ #
10
+
11
+ if Rails.env.development?
12
+ neo4j_url = "http://localhost:7474"
13
+ elsif Rails.env.test?
14
+ neo4j_url = "http://localhost:7574"
15
+ elsif Rails.env.production?
16
+ raise 'TODO: read the neo4j server connection from config file.'
17
+ end
18
+
19
+ uri = URI.parse(neo4j_url)
20
+
21
+ $neo = Neography::Rest.new(uri.to_s)
22
+
23
+ Neography.configure do |c|
24
+ c.server = uri.host
25
+ c.port = uri.port
26
+
27
+ if uri.user && uri.password
28
+ c.authentication = 'basic'
29
+ c.username = uri.user
30
+ c.password = uri.password
31
+ end
32
+ end
33
+
34
+ Neoid.db = $neo
35
+
36
+ Neoid.configure do |c|
37
+ # should Neoid create sub-reference from the ref node (id#0) to every node-model? default: true
38
+ c.enable_subrefs = false
39
+ end
@@ -0,0 +1,10 @@
1
+ class CreateLinks < ActiveRecord::Migration
2
+ def change
3
+ create_table :neo4j_ancestry_links do |t|
4
+ t.integer :parent_id
5
+ t.string :parent_type
6
+ t.integer :child_id
7
+ t.string :child_type
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,111 @@
1
+ module Neo4jAncestry
2
+ module ActiveRecordAdditions
3
+ require 'neo4j_ancestry/railtie' if defined?(Rails)
4
+
5
+ # Example options:
6
+ # parent_class_names: %w(Group),
7
+ # child_class_names: %w(Group User)
8
+ #
9
+ def has_neo4j_ancestry(options)
10
+
11
+ link_class_name = 'Neo4jAncestry::Link'
12
+
13
+ # Links (direct relationships between objects) are stored
14
+ # via ActiveRecord in the mysql database. (The neo4j database contains only
15
+ # redundant information and is used for fast queries.)
16
+ #
17
+ has_many :links_as_parent, foreign_key: :parent_id, class_name: link_class_name
18
+ has_many :links_as_child, foreign_key: :child_id, class_name: link_class_name
19
+
20
+ parent_class_names = options[:parent_class_names] || []
21
+ child_class_names = options[:child_class_names] || []
22
+
23
+ # links_as_child for specific parent object classes and
24
+ # links_as_parent for specific child object classes, e.g.
25
+ # group.links_as_child_for_groups
26
+ # group.links_as_parent_for_groups
27
+ # group.links_as_parent_for_users
28
+ #
29
+ parent_class_names.each do |parent_class_name|
30
+ has_many_for_rails_3_and_4(
31
+ "links_as_child_for_#{parent_class_name.underscore.pluralize}".to_sym,
32
+ { parent_type: parent_class_name },
33
+ { as: :child, class_name: link_class_name } )
34
+ end
35
+ child_class_names.each do |child_class_name|
36
+ has_many_for_rails_3_and_4(
37
+ "links_as_parent_for_#{child_class_name.underscore.pluralize}".to_sym,
38
+ { child_type: child_class_name },
39
+ { as: :parent, class_name: link_class_name } )
40
+ end
41
+
42
+ # parent and child associations for specific object classes, e.g.
43
+ # group.parent_groups
44
+ # group.child_groups
45
+ # group.child_users
46
+ #
47
+ parent_class_names.each do |parent_class_name|
48
+ has_many(
49
+ "parent_#{parent_class_name.underscore.pluralize}".to_sym,
50
+ through: "links_as_child_for_#{parent_class_name.underscore.pluralize}".to_sym,
51
+ as: :structureable,
52
+ foreign_key: :parent_id, source: 'parent',
53
+ source_type: parent_class_name )
54
+ end
55
+ child_class_names.each do |child_class_name|
56
+ has_many(
57
+ "child_#{child_class_name.underscore.pluralize}".to_sym,
58
+ through: "links_as_parent_for_#{child_class_name.underscore.pluralize}".to_sym,
59
+ as: :structureable,
60
+ foreign_key: :child_id, source: 'child',
61
+ source_type: child_class_name )
62
+ end
63
+
64
+ # Use the neoid gem to have this object represented as node
65
+ # in the neo4j graph database.
66
+ #
67
+ include Neoid::Node
68
+
69
+ # Copy the name attribute to the neo4j nodes.
70
+ # Other attributes can be copied as well by using the 'attributes_to_copy_to_neo4j'.
71
+ #
72
+ attributes_to_copy_to_neo4j do |c|
73
+ c.field :name
74
+ end
75
+
76
+ # Include the instance methods for interaction with the neo4j graph.
77
+ #
78
+ include Neo4jAncestry::NodeInstanceMethods
79
+
80
+ end
81
+
82
+ # Attributes to copy over to the neo4j database.
83
+ # This is just a wrapper for the 'neoidable' method of the neoid gem.
84
+ # https://github.com/elado/neoid
85
+ #
86
+ # Example:
87
+ # attributes_to_copy_to_neo4j do |c|
88
+ # c.field :name
89
+ # c.field :name_length do
90
+ # self.name.length
91
+ # end
92
+ # end
93
+ #
94
+ def attributes_to_copy_to_neo4j(&block)
95
+ neoidable(&block)
96
+ end
97
+
98
+ # The has_many method changes from Rails 3 to Rails 4.
99
+ # Since this gem supports both rails versions, this method
100
+ # is a wrapper.
101
+ #
102
+ def has_many_for_rails_3_and_4(association_name, conditions_hash, options)
103
+ if Rails.version.start_with? "4"
104
+ has_many(association_name, -> { where conditions_hash }, options)
105
+ elsif Rails.version.start_with? "3"
106
+ has_many(association_name, options.merge({conditions: conditions_hash}))
107
+ end
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,28 @@
1
+ module Neo4jAncestry
2
+ def self.table_name_prefix
3
+ 'neo4j_ancestry_'
4
+ end
5
+
6
+ class Link < ActiveRecord::Base
7
+
8
+ # ActiveRecord database columns
9
+ #
10
+ # create_table :neo4j_ancestry_links do |t|
11
+ # t.integer :parent_id
12
+ # t.string :parent_type
13
+ # t.integer :child_id
14
+ # t.integer :child_type
15
+ # end
16
+ #
17
+
18
+ belongs_to :parent, polymorphic: true
19
+ belongs_to :child, polymorphic: true
20
+
21
+ include Neoid::Relationship
22
+
23
+ neoidable do |c|
24
+ c.relationship start_node: :parent, end_node: :child, type: :is_parent_of
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,93 @@
1
+ module Neo4jAncestry
2
+ module NodeInstanceMethods
3
+
4
+ # The neoid gem provides a neo_node method, which returns an object
5
+ # representing the node in the neo4j database that corresponds to this
6
+ # object.
7
+ #
8
+ # Overriding the neo_node method ensures that for STI the same neo_node
9
+ # is returned for the same object regardless of the subclass.
10
+ #
11
+ # That means: group.neo_node == group.becomes(SpecialGroup).neo_node
12
+ #
13
+ def neo_node
14
+ super || self.becomes(self.class.base_class).neo_node
15
+ end
16
+
17
+ # The unique id of the neo4j node that corresponds to this object.
18
+ #
19
+ def neo_id
20
+ neo_node.try(:neo_id)
21
+ end
22
+
23
+ # Methods to query the neo4j database for parents, children,
24
+ # ancestors, descendants and siblings.
25
+ def parents
26
+ find_related_nodes_via_cypher("
27
+ match (parents)-[:is_parent_of]->(self)
28
+ return parents
29
+ ")
30
+ end
31
+ def children
32
+ find_related_nodes_via_cypher("
33
+ match (self)-[:is_parent_of]->(children)
34
+ return children
35
+ ")
36
+ end
37
+ def ancestors
38
+ find_related_nodes_via_cypher("
39
+ match (ancestors)-[:is_parent_of*1..100]->(self)
40
+ return ancestors
41
+ ").uniq
42
+ end
43
+ def descendants
44
+ find_related_nodes_via_cypher("
45
+ match (self)-[:is_parent_of*1..100]->(descendants)
46
+ return descendants
47
+ ").uniq
48
+ end
49
+ def siblings
50
+ find_related_nodes_via_cypher("
51
+ match (self)<-[:is_parent_of]-(parent)-[:is_parent_of]->(siblings)
52
+ return siblings
53
+ ").uniq
54
+ end
55
+
56
+ # This method returns all ActiveRecord objects found by a cypher
57
+ # neo4j query defined through the given query_string.
58
+ #
59
+ # Within the query_string, no START expression is needed,
60
+ # because the start node is given by the neo_node of this
61
+ # structureable object. It is referred to just by 'self'.
62
+ #
63
+ # Example:
64
+ # group.find_related_nodes_via_cypher("
65
+ # match (self)-[:is_parent_of]->(children)
66
+ # return children
67
+ # ") # => [child_group1, child_group2, ...]
68
+ #
69
+ def find_related_nodes_via_cypher(query_string)
70
+ query_string = "
71
+ start self=node(#{neo_id})
72
+ #{query_string}
73
+ "
74
+ cypher_results_to_objects(
75
+ Neoid.db.execute_query(query_string)
76
+ )
77
+ end
78
+
79
+ # This method returns the ActiveRecord objects that match the
80
+ # given cypher query result.
81
+ #
82
+ # For an example, have a look at the method
83
+ # find_related_nodes_via_cypher.
84
+ #
85
+ def cypher_results_to_objects(cypher_results)
86
+ cypher_results["data"].collect do |result|
87
+ result.first["data"]["ar_type"].constantize.find(result.first["data"]["ar_id"])
88
+ end
89
+ end
90
+ private :cypher_results_to_objects
91
+
92
+ end
93
+ end