Skip to content
Permalink
Browse files

Merge pull request #411 from andreasronge/activerel

Activerel closes #393
  • Loading branch information...
andreasronge committed Aug 17, 2014
2 parents f997f43 + f9ac250 commit 3b931758042ef5d67888e1bdd1307198f2e275bf
Showing with 1,803 additions and 984 deletions.
  1. +3 −2 Gemfile
  2. +9 −3 example/blog/app/controllers/comments_controller.rb
  3. +3 −2 example/blog/app/models/comment.rb
  4. +2 −1 example/blog/app/models/post.rb
  5. +15 −0 example/blog/app/models/post_comment.rb
  6. +12 −15 example/blog/app/views/posts/show.html.erb
  7. +21 −4 lib/neo4j.rb
  8. +5 −35 lib/neo4j/active_node.rb
  9. +1 −34 lib/neo4j/active_node/callbacks.rb
  10. +35 −16 lib/neo4j/active_node/has_n/association.rb
  11. +0 −90 lib/neo4j/active_node/has_n/nodes.rb
  12. +1 −1 lib/neo4j/active_node/id_property.rb
  13. +2 −2 lib/neo4j/active_node/initialize.rb
  14. +3 −3 lib/neo4j/active_node/labels.rb
  15. +50 −0 lib/neo4j/active_node/node_wrapper.rb
  16. +2 −205 lib/neo4j/active_node/persistence.rb
  17. +1 −194 lib/neo4j/active_node/property.rb
  18. +0 −254 lib/neo4j/active_node/quick_query.rb
  19. +2 −2 lib/neo4j/active_node/rels.rb
  20. +9 −41 lib/neo4j/active_node/validations.rb
  21. +34 −0 lib/neo4j/active_rel.rb
  22. +13 −0 lib/neo4j/active_rel/callbacks.rb
  23. +30 −0 lib/neo4j/active_rel/initialize.rb
  24. +80 −0 lib/neo4j/active_rel/persistence.rb
  25. +64 −0 lib/neo4j/active_rel/property.rb
  26. +66 −0 lib/neo4j/active_rel/query.rb
  27. +18 −0 lib/neo4j/active_rel/rel_wrapper.rb
  28. +42 −0 lib/neo4j/active_rel/related_node.rb
  29. +9 −0 lib/neo4j/active_rel/validations.rb
  30. +34 −0 lib/neo4j/shared.rb
  31. +40 −0 lib/neo4j/shared/callbacks.rb
  32. +6 −2 lib/neo4j/{active_node → shared}/identity.rb
  33. +214 −0 lib/neo4j/shared/persistence.rb
  34. +220 −0 lib/neo4j/shared/property.rb
  35. +48 −0 lib/neo4j/shared/validations.rb
  36. +2 −50 lib/neo4j/wrapper.rb
  37. +2 −2 spec/e2e/active_model_spec.rb
  38. +1 −1 spec/e2e/attributes_spec.rb
  39. +1 −1 spec/e2e/id_property_spec.rb
  40. +2 −2 spec/e2e/rels_spec.rb
  41. +2 −2 spec/integration/node_persistence_spec.rb
  42. +3 −1 spec/support/matchers.rb
  43. +21 −0 spec/unit/active_rel/active_rel_spec.rb
  44. +56 −0 spec/unit/active_rel/callbacks_spec.rb
  45. +18 −0 spec/unit/active_rel/initialize_spec.rb
  46. +155 −0 spec/unit/active_rel/persistence_spec.rb
  47. +99 −0 spec/unit/active_rel/property_spec.rb
  48. +134 −0 spec/unit/active_rel/query_spec.rb
  49. +46 −0 spec/unit/active_rel/rel_wrapper_spec.rb
  50. +104 −0 spec/unit/active_rel/related_node_spec.rb
  51. +33 −0 spec/unit/association_spec.rb
  52. +4 −4 spec/unit/identity_spec.rb
  53. +10 −10 spec/unit/persistance_spec.rb
  54. +12 −0 spec/unit/shared/property_spec.rb
  55. +4 −4 spec/unit/validation_spec.rb
  56. +0 −1 spec/unit/wrapper_spec.rb
@@ -2,8 +2,9 @@ source 'http://rubygems.org'

gemspec

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

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

gem 'coveralls', require: false
@@ -14,10 +14,16 @@ def create

respond_to do |format|
if @comment.save
# create a relationship with a created property between post and comment
@post.comments.create(@comment, :created => Time.now.to_i)
# alternative
# using the ActiveRel model to create the relationship
# callbacks, validations would run
# it will be timestamped as any other model since a :created_at property is present
PostComment.create(from_node: @post, to_node: @comment)
# alternatives
# @post.comments << @comment
# or
# create a relationship with a created property between post and comment
# @post.comments.create(@comment, :created => Time.now.to_i)


format.html { redirect_to @post, notice: 'Comment was successfully created.' }
format.json { render action: 'show', status: :created, location: @comment }
@@ -4,5 +4,6 @@ class Comment
property :text

index :title
has_one :in, :post
end
has_one :in, :post, origin: :comments, rel_class: PostComment

end
@@ -21,5 +21,6 @@ class Post
# self.title.urlize # uses https://github.com/cheef/string-urlize gem
# end

has_many :out, :comments
has_many :out, :comments, type: 'stated_opinions', rel_class: PostComment

end
@@ -0,0 +1,15 @@
class PostComment
include Neo4j::ActiveRel
# would accept :any instead of model constant
from_class Post
to_class Comment

#or
# start_class Post
# end_class Comment

type 'stated_opinions'

# automatically adds timestamps
property :created_at
end
@@ -9,30 +9,27 @@
<b>Text:</b>
<%= @post.text %>

<br />

<b>Score:</b>
<%= @post.score %>

</p>

<h3>Comments</h3>

<table>

<!--Finding all relationship: @post.comments_rel-->
<!--Finding, alternative all relationship, a.rels(dir: :outgoing, type: Post.comments)-->
<!--Without rels, @post.each -->
<!--Finding all relationships: @post.comments.each_rel-->
<!--Finding, alternative all relationship, a.rels(dir: :outgoing, type: Post.comments)-->

<% @post.comments.each do |comment| %>
<tr>
<td>
<%= comment.title %>
</td>

<td>
<%= link_to 'Destroy', [@post,comment], method: :delete%>
</td>
</tr>
<% @post.comments.each_with_rel do |comment, rel| %>
<strong>Title</strong>&nbsp;<%= comment.title %><br />
<strong>Created at</strong>&nbsp;<%= rel.created_at.strftime("%D, %H:%m") %><br />
<%= link_to 'Destroy', [@post,comment], method: :delete%>
&nbsp;<br />
&nbsp;<br />
<% end %>
</table>


<p>
<%= link_to 'New Comment', new_post_comment_path(@post) %>
@@ -17,9 +17,28 @@
require 'active_attr'
require 'neo4j/config'
require 'neo4j/wrapper'
require 'neo4j/active_rel/rel_wrapper'
require 'neo4j/active_node/node_wrapper'
require 'neo4j/type_converters'
require "neo4j/active_node/labels"
require 'neo4j/active_node/identity'
require 'neo4j/paginated'

require 'neo4j/shared/callbacks'
require 'neo4j/shared/property'
require 'neo4j/shared/persistence'
require 'neo4j/shared/validations'
require 'neo4j/shared/identity'
require 'neo4j/shared'

require 'neo4j/active_rel/callbacks'
require 'neo4j/active_rel/initialize'
require 'neo4j/active_rel/property'
require 'neo4j/active_rel/persistence'
require 'neo4j/active_rel/validations'
require 'neo4j/active_rel/query'
require 'neo4j/active_rel/related_node'
require 'neo4j/active_rel'

require 'neo4j/active_node/labels'
require 'neo4j/active_node/id_property'
require 'neo4j/active_node/callbacks'
require 'neo4j/active_node/initialize'
@@ -29,11 +48,9 @@
require 'neo4j/active_node/rels'
require 'neo4j/active_node/has_n'
require 'neo4j/active_node/has_n/association'
require 'neo4j/active_node/has_n/nodes'
require 'neo4j/active_node/query/query_proxy'
require 'neo4j/active_node/query'
require 'neo4j/active_node/serialized_properties'
require 'neo4j/paginated'
require 'neo4j/active_node'

require 'neo4j/active_node/orm_adapter'
@@ -23,55 +23,25 @@ module Neo4j
#
module ActiveNode
extend ActiveSupport::Concern
extend ActiveModel::Naming

include ActiveModel::Conversion
include ActiveModel::Serializers::Xml
include ActiveModel::Serializers::JSON

include Neo4j::Shared
include Neo4j::ActiveNode::Initialize
include Neo4j::ActiveNode::Identity
include Neo4j::ActiveNode::IdProperty
include Neo4j::ActiveNode::Persistence
include Neo4j::ActiveNode::SerializedProperties
include Neo4j::ActiveNode::Property
include Neo4j::ActiveNode::Query
include Neo4j::ActiveNode::Labels
include Neo4j::ActiveNode::Persistence
include Neo4j::ActiveNode::Validations
include Neo4j::ActiveNode::Callbacks
include Neo4j::ActiveNode::Query
include Neo4j::ActiveNode::Labels
include Neo4j::ActiveNode::Rels
include Neo4j::ActiveNode::HasN

def wrapper
self
end

def neo4j_obj
_persisted_node || raise("Tried to access native neo4j object on a non persisted object")
end

module ClassMethods
def neo4j_session_name (name)
@neo4j_session_name = name
end

def neo4j_session
if @neo4j_session_name
Neo4j::Session.named(@neo4j_session_name) || raise("#{self.name} is configured to use a neo4j session named #{@neo4j_session_name}, but no such session is registered with Neo4j::Session")
else
Neo4j::Session.current
end
end
_persisted_obj || raise("Tried to access native neo4j object on a non persisted object")
end

included do
self.include_root_in_json = true


def self.i18n_scope
:neo4j
end

def self.inherited(other)
inherited_indexes(other) if self.respond_to?(:indexed_properties)
attributes.each_pair do |k,v|
@@ -2,40 +2,7 @@ module Neo4j
module ActiveNode
module Callbacks #:nodoc:
extend ActiveSupport::Concern

module ClassMethods
include ActiveModel::Callbacks
end

included do
include ActiveModel::Validations::Callbacks

define_model_callbacks :initialize, :find, :only => :after
define_model_callbacks :save, :create, :update, :destroy
end

def destroy #:nodoc:
run_callbacks(:destroy) { super }
end

def touch(*) #:nodoc:
run_callbacks(:touch) { super }
end

private

def create_or_update #:nodoc:
run_callbacks(:save) { super }
end

def create_model #:nodoc:
run_callbacks(:create) { super }
end

def update_model(*) #:nodoc:
run_callbacks(:update) { super }
end
include Neo4j::Shared::Callbacks
end

end
end
@@ -7,26 +7,16 @@ class Association
attr_reader :type, :name, :relationship, :direction

def initialize(type, direction, name, options = {})
raise ArgumentError, "Invalid association type: #{type.inspect}" if not [:has_many, :has_one].include?(type.to_sym)
raise ArgumentError, "Invalid direction: #{direction.inspect}" if not [:out, :in, :both].include?(direction.to_sym)
check_valid_type_and_dir(type, direction)
@type = type.to_sym
@name = name
@direction = direction.to_sym
raise ArgumentError, "Cannot specify both :type and :origin (#{base_declaration})" if options[:type] && options[:origin]

@target_class_name_from_name = name.to_s.classify
@target_class_option = target_class_option(options)
@callbacks = {before: options[:before], after: options[:after]}
@relationship_type = options[:type] && options[:type].to_sym
@origin = options[:origin] && options[:origin].to_sym
set_vars_from_options(options)
end

def target_class_option(options)
if options[:model_class].nil?
@target_class_name_from_name
elsif options[:model_class]
options[:model_class]
end
options[:model_class].nil? ? @target_class_name_from_name : options[:model_class]
end

# Return cypher partial query string for the relationship part of a MATCH (arrow / relationship definition)
@@ -35,7 +25,6 @@ def arrow_cypher(var = nil, properties = {}, create = false)

relationship_type = relationship_type(create)
relationship_name_cypher = ":`#{relationship_type}`" if relationship_type

properties_string = get_properties_string(properties)
relationship_cypher = get_relationship_cypher(var, relationship_name_cypher, properties_string)
get_direction(relationship_cypher, create)
@@ -63,9 +52,12 @@ def perform_callback(caller, other_node, type)
end

def relationship_type(create = false)
if @relationship_type
case
when @relationship_class
@relationship_class._type
when @relationship_type
@relationship_type
elsif @origin
when @origin
origin_type
else
(create || exceptional_target_class?) && "##{@name}"
@@ -91,7 +83,9 @@ def get_relationship_cypher(var, relationship_name_cypher, properties_string)
end

def get_properties_string(properties)
properties[Neo4j::Config.class_name_property] = @relationship_class.name if @relationship_class
p = properties.map do |key, value|
next if key == :_classname
"#{key}: #{value.inspect}"
end.join(', ')
p.size == 0 ? '' : " {#{p}}"
@@ -101,13 +95,38 @@ def origin_type
target_class.associations[@origin].relationship_type
end

def relationship_class
@relationship_class
end

private

def set_vars_from_options(options)
validate_option_combinations(options)
@target_class_option = target_class_option(options)
@callbacks = {before: options[:before], after: options[:after]}
@origin = options[:origin] && options[:origin].to_sym
@relationship_class = options[:rel_class]
@relationship_type = options[:type] && options[:type].to_sym
end

# Return basic details about association as declared in the model
# @example
# has_many :in, :bands
def base_declaration
"#{type} #{direction.inspect}, #{name.inspect}"
end

def check_valid_type_and_dir(type, direction)
raise ArgumentError, "Invalid association type: #{type.inspect}" if not [:has_many, :has_one].include?(type.to_sym)
raise ArgumentError, "Invalid direction: #{direction.inspect}" if not [:out, :in, :both].include?(direction.to_sym)
end

def validate_option_combinations(options)
raise ArgumentError, "Cannot specify both :type and :origin (#{base_declaration})" if options[:type] && options[:origin]
raise ArgumentError, "Cannot specify both :type and :rel_class (#{base_declaration})" if options[:type] && options[:rel_class]
raise ArgumentError, "Cannot specify both :origin and :rel_class (#{base_declaration}" if options[:origin] && options[:rel_class]
end

# Determine if model class as derived from the association name would be different than the one specified via the model_class key
# @example

0 comments on commit 3b93175

Please sign in to comment.
You can’t perform that action at this time.