Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion lib/neo4j/active_node/labels.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,26 @@ def destroy_all

# @return [Array{Symbol}] all the labels that this class has
def mapped_label_names
self.ancestors.find_all { |a| a.respond_to?(:mapped_label_name) }.map { |a| a.mapped_label_name.to_sym }
self.ancestors.find_all { |a| a.respond_to?(:mapped_label_name) }.inject([]) do |labels, a|
labels.push *a.all_mapped_label_names.map(&:to_sym)
end
end

# @return [Symbol] the label that this class has which corresponds to a Ruby class
def mapped_label_name
@mapped_label_name || label_for_model
end

# @return [Array{Symbol}] the additional, user given labels that this class has
def additional_mapped_label_names
@additional_mapped_label_names || []
end

# @return [Array{Symbol}] the mapped_label_name and additional_mapped_label_names of this class
def all_mapped_label_names
[mapped_label_name, additional_mapped_label_names].flatten
end

# @return [Neo4j::Label] the label for this class
def mapped_label
Neo4j::Core::Label.new(mapped_label_name, neo4j_session)
Expand Down Expand Up @@ -166,6 +178,17 @@ def mapped_label_name=(name)
@mapped_label_name = name.to_sym
end

def additional_mapped_label_names=(given_names)
names = case given_names
when Array then given_names
when String then [given_names]
else
fail '"additional_mapped_label_names" must be a string or array of strings'
end

@additional_mapped_label_names = names.map(&:to_sym)
end

# rubocop:disable Style/AccessorMethodName
def set_mapped_label_name(name)
ActiveSupport::Deprecation.warn 'set_mapped_label_name is deprecated, use self.mapped_label_name= instead.', caller
Expand Down
26 changes: 26 additions & 0 deletions spec/integration/label_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,31 @@ def self.neo4j_session
extend Neo4j::ActiveNode::Labels::ClassMethods
end

module SomeAdditionalLabelMixin
def self.mapped_label_name
:some_label
end

def self.additional_mapped_label_names
[:additional_label, :another_additional_label]
end

def self.neo4j_session
current_session
end

extend Neo4j::ActiveNode::Query::ClassMethods
extend Neo4j::ActiveNode::Labels::ClassMethods
end

stub_active_node_class('SomeLabelClass') do
include SomeLabelMixin
end

stub_active_node_class('SomeAdditionalLabelClass') do
include SomeAdditionalLabelMixin
end

stub_active_node_class('RelationTestClass') do
has_one :in, :test_class, type: nil
end
Expand All @@ -44,6 +65,11 @@ def self.neo4j_session
p = SomeLabelClass.create
expect(p.labels.to_a).to match_array([:SomeLabelClass, :some_label])
end

it "sets label for mixin's additional classes" do
p = SomeAdditionalLabelClass.create
expect(p.labels.to_a).to match_array([:SomeAdditionalLabelClass, :some_label, :additional_label, :another_additional_label])
end
end

describe 'all' do
Expand Down
195 changes: 155 additions & 40 deletions spec/unit/active_node/labels_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ def self.name
end
end

describe 'set_additional_mapped_label_names' do
it 'sets a single additional label name for clazz' do
clazz = Class.new { extend Neo4j::ActiveNode::Labels::ClassMethods }
clazz.send(:additional_mapped_label_names=, 'foo')
expect(clazz.additional_mapped_label_names).to eq([:foo])
end

it 'sets multiple additional label names for clazz' do
clazz = Class.new { extend Neo4j::ActiveNode::Labels::ClassMethods }
clazz.send(:additional_mapped_label_names=, ['foo', 'bar'])
expect(clazz.additional_mapped_label_names).to eq([:foo, :bar])
end
end

describe 'label' do
it 'wraps the mapped_label_name in a Neo4j::Core::Label object' do
clazz = Class.new do
Expand All @@ -76,68 +90,160 @@ def self.name
end

describe 'mapped_label_names' do
it 'returns the label of a class' do
clazz = Class.new do
extend Neo4j::ActiveNode::Labels::ClassMethods
def self.name
'mylabel'
describe 'when class has one label' do
it 'returns the label of a class' do
clazz = Class.new do
extend Neo4j::ActiveNode::Labels::ClassMethods
def self.name
'mylabel'
end
end
expect(clazz.mapped_label_names).to eq([:mylabel])
end
expect(clazz.mapped_label_names).to eq([:mylabel])
end

it 'returns all labels for inherited ancestors which have a label method' do
base_class = Class.new do
def self.mapped_label_name
'base'
it 'returns all labels for inherited ancestors which have a label method' do
base_class = Class.new do
def self.mapped_label_name; end

def self.all_mapped_label_names
['base']
end
end
end

middle_class = Class.new(base_class) do
extend Neo4j::ActiveNode::Labels::ClassMethods
middle_class = Class.new(base_class) do
extend Neo4j::ActiveNode::Labels::ClassMethods

def self.mapped_label_name
'middle'
def self.mapped_label_name
'middle'
end
end
end

top_class = Class.new(middle_class) do
extend Neo4j::ActiveNode::Labels::ClassMethods
top_class = Class.new(middle_class) do
extend Neo4j::ActiveNode::Labels::ClassMethods

def self.mapped_label_name
'top'
def self.mapped_label_name
'top'
end
end

# notice the order is important since it will try to load and map in that order
expect(middle_class.mapped_label_names).to eq([:middle, :base])
expect(top_class.mapped_label_names).to eq([:top, :middle, :base])
end

# notice the order is important since it will try to load and map in that order
expect(middle_class.mapped_label_names).to eq([:middle, :base])
expect(top_class.mapped_label_names).to eq([:top, :middle, :base])
end
it 'returns all labels for included modules which have a label class method' do
module1 = Module.new do
def self.mapped_label_name; end

def self.all_mapped_label_names
['module1']
end
end

module2 = Module.new do
def self.mapped_label_name; end

it 'returns all labels for included modules which have a label class method' do
module1 = Module.new do
def self.mapped_label_name
'module1'
def self.all_mapped_label_names
['module2']
end
end

clazz = Class.new do
extend Neo4j::ActiveNode::Labels::ClassMethods
include module1
include module2

def self.name
'module'
end
end

expect(clazz.mapped_label_names).to match_array([:module, :module1, :module2])
end
end

describe 'when class has additional labels' do
it 'returns all labels of a class' do
clazz = Class.new do
extend Neo4j::ActiveNode::Labels::ClassMethods
def self.name
'mylabel'
end

module2 = Module.new do
def self.mapped_label_name
'module2'
def self.additional_mapped_label_names
['foo', 'bar']
end
end
expect(clazz.mapped_label_names).to eq([:mylabel, :foo, :bar])
end

clazz = Class.new do
extend Neo4j::ActiveNode::Labels::ClassMethods
include module1
include module2
it 'returns all labels for inherited ancestors which have a label method' do
base_class = Class.new do
def self.mapped_label_name; end

def self.name
'module'
def self.all_mapped_label_names
['base']
end
end

middle_class = Class.new(base_class) do
extend Neo4j::ActiveNode::Labels::ClassMethods

def self.mapped_label_name
'middle'
end

def self.additional_mapped_label_names
['foo']
end
end

top_class = Class.new(middle_class) do
extend Neo4j::ActiveNode::Labels::ClassMethods

def self.mapped_label_name
'top'
end

def self.additional_mapped_label_names
['bar']
end
end

# notice the order is important since it will try to load and map in that order
expect(middle_class.mapped_label_names).to eq([:middle, :foo, :base])
expect(top_class.mapped_label_names).to eq([:top, :bar, :middle, :foo, :base])
end

expect(clazz.mapped_label_names).to match_array([:module, :module1, :module2])
it 'returns all labels for included modules which have a label class method' do
module1 = Module.new do
def self.mapped_label_name; end

def self.all_mapped_label_names
['module1', 'foo']
end
end

module2 = Module.new do
def self.mapped_label_name; end

def self.all_mapped_label_names
['module2', 'bar', 'car']
end
end

clazz = Class.new do
extend Neo4j::ActiveNode::Labels::ClassMethods
include module1
include module2

def self.name
'module'
end
end

expect(clazz.mapped_label_names).to match_array([:module, :module1, :foo, :module2, :bar, :car])
end
end
end

Expand All @@ -150,6 +256,11 @@ class URL
include Neo4j::ActiveNode
end

class Author
include Neo4j::ActiveNode
self.additional_mapped_label_names = 'URL'
end

module DataSource
class URL < ::URL
self.mapped_label_name = 'DataSource'
Expand All @@ -158,10 +269,14 @@ class URL < ::URL
class Event < URL
self.mapped_label_name = 'Event'
end

class Author < URL
self.additional_mapped_label_names = 'Person'
end
end

it 'returns the correct model for the node' do
classes = [Event, URL, DataSource::URL, DataSource::Event]
classes = [Event, URL, Author, DataSource::URL, DataSource::Event, DataSource::Author]

# TODO: not sure why this is not being called when the class is defined
classes.reverse_each { |c| Neo4j::ActiveNode::Labels.add_wrapped_class(c) }
Expand Down