neo4j 1.0.0.beta.21-java
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +141 -0
- data/CONTRIBUTORS +17 -0
- data/Gemfile +16 -0
- data/README.rdoc +135 -0
- data/lib/generators/neo4j.rb +65 -0
- data/lib/generators/neo4j/model/model_generator.rb +39 -0
- data/lib/generators/neo4j/model/templates/model.erb +7 -0
- data/lib/neo4j.rb +77 -0
- data/lib/neo4j/config.rb +153 -0
- data/lib/neo4j/database.rb +56 -0
- data/lib/neo4j/equal.rb +21 -0
- data/lib/neo4j/event_handler.rb +116 -0
- data/lib/neo4j/index/class_methods.rb +62 -0
- data/lib/neo4j/index/index.rb +33 -0
- data/lib/neo4j/index/indexer.rb +312 -0
- data/lib/neo4j/index/indexer_registry.rb +68 -0
- data/lib/neo4j/index/lucene_query.rb +191 -0
- data/lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
- data/lib/neo4j/jars/lucene-core-3.0.2.jar +0 -0
- data/lib/neo4j/jars/neo4j-index-1.2-1.2.M03.jar +0 -0
- data/lib/neo4j/jars/neo4j-kernel-1.2-1.2.M03.jar +0 -0
- data/lib/neo4j/jars/neo4j-lucene-index-0.2-1.2.M03.jar +0 -0
- data/lib/neo4j/load.rb +21 -0
- data/lib/neo4j/mapping/class_methods/init_node.rb +50 -0
- data/lib/neo4j/mapping/class_methods/init_rel.rb +35 -0
- data/lib/neo4j/mapping/class_methods/list.rb +13 -0
- data/lib/neo4j/mapping/class_methods/property.rb +82 -0
- data/lib/neo4j/mapping/class_methods/relationship.rb +91 -0
- data/lib/neo4j/mapping/class_methods/rule.rb +295 -0
- data/lib/neo4j/mapping/decl_relationship_dsl.rb +214 -0
- data/lib/neo4j/mapping/has_list.rb +134 -0
- data/lib/neo4j/mapping/has_n.rb +83 -0
- data/lib/neo4j/mapping/node_mixin.rb +112 -0
- data/lib/neo4j/mapping/relationship_mixin.rb +120 -0
- data/lib/neo4j/model.rb +4 -0
- data/lib/neo4j/neo4j.rb +95 -0
- data/lib/neo4j/node.rb +131 -0
- data/lib/neo4j/node_mixin.rb +4 -0
- data/lib/neo4j/node_relationship.rb +149 -0
- data/lib/neo4j/node_traverser.rb +157 -0
- data/lib/neo4j/property.rb +111 -0
- data/lib/neo4j/rails/attributes.rb +155 -0
- data/lib/neo4j/rails/callbacks.rb +34 -0
- data/lib/neo4j/rails/finders.rb +134 -0
- data/lib/neo4j/rails/lucene_connection_closer.rb +19 -0
- data/lib/neo4j/rails/mapping/property.rb +60 -0
- data/lib/neo4j/rails/model.rb +105 -0
- data/lib/neo4j/rails/persistence.rb +260 -0
- data/lib/neo4j/rails/railtie.rb +21 -0
- data/lib/neo4j/rails/relationships/mapper.rb +96 -0
- data/lib/neo4j/rails/relationships/relationship.rb +30 -0
- data/lib/neo4j/rails/relationships/relationships.rb +60 -0
- data/lib/neo4j/rails/serialization.rb +25 -0
- data/lib/neo4j/rails/timestamps.rb +65 -0
- data/lib/neo4j/rails/transaction.rb +67 -0
- data/lib/neo4j/rails/tx_methods.rb +15 -0
- data/lib/neo4j/rails/validations.rb +38 -0
- data/lib/neo4j/rails/validations/non_nil.rb +11 -0
- data/lib/neo4j/rails/validations/uniqueness.rb +37 -0
- data/lib/neo4j/relationship.rb +169 -0
- data/lib/neo4j/relationship_mixin.rb +4 -0
- data/lib/neo4j/relationship_traverser.rb +92 -0
- data/lib/neo4j/to_java.rb +31 -0
- data/lib/neo4j/transaction.rb +68 -0
- data/lib/neo4j/type_converters.rb +117 -0
- data/lib/neo4j/version.rb +3 -0
- data/lib/orm_adapter/adapters/neo4j.rb +55 -0
- data/lib/tmp/neo4j/active_tx_log +1 -0
- data/lib/tmp/neo4j/index/lucene-store.db +0 -0
- data/lib/tmp/neo4j/index/lucene.log.active +0 -0
- data/lib/tmp/neo4j/lucene-fulltext/lucene-store.db +0 -0
- data/lib/tmp/neo4j/lucene-fulltext/lucene.log.active +0 -0
- data/lib/tmp/neo4j/lucene/lucene-store.db +0 -0
- data/lib/tmp/neo4j/lucene/lucene.log.active +0 -0
- data/lib/tmp/neo4j/messages.log +85 -0
- data/lib/tmp/neo4j/neostore +0 -0
- data/lib/tmp/neo4j/neostore.id +0 -0
- data/lib/tmp/neo4j/neostore.nodestore.db +0 -0
- data/lib/tmp/neo4j/neostore.nodestore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.arrays +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.arrays.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.index +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.index.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.index.keys +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.index.keys.id +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.strings +0 -0
- data/lib/tmp/neo4j/neostore.propertystore.db.strings.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshipstore.db +0 -0
- data/lib/tmp/neo4j/neostore.relationshipstore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.id +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.names +0 -0
- data/lib/tmp/neo4j/neostore.relationshiptypestore.db.names.id +0 -0
- data/lib/tmp/neo4j/nioneo_logical.log.active +0 -0
- data/lib/tmp/neo4j/tm_tx_log.1 +0 -0
- data/neo4j.gemspec +31 -0
- metadata +216 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module Neo4j
|
2
|
+
class Railtie < ::Rails::Railtie
|
3
|
+
config.neo4j = ActiveSupport::OrderedOptions.new
|
4
|
+
|
5
|
+
initializer "neo4j.tx" do |app|
|
6
|
+
app.config.middleware.use Neo4j::Rails::LuceneConnectionCloser
|
7
|
+
end
|
8
|
+
|
9
|
+
# Add ActiveModel translations to the I18n load_path
|
10
|
+
initializer "i18n" do |app|
|
11
|
+
config.i18n.load_path += Dir[File.join(File.dirname(__FILE__), '..', '..', '..', 'config', 'locales', '*.{rb,yml}')]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Starting Neo after :load_config_initializers allows apps to
|
15
|
+
# register migrations in config/initializers
|
16
|
+
initializer "neo4j.start", :after => :load_config_initializers do |app|
|
17
|
+
Neo4j::Config.setup.merge!(app.config.neo4j.to_hash)
|
18
|
+
Neo4j.start
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
module Relationships
|
4
|
+
|
5
|
+
class Mapper
|
6
|
+
def initialize(rel_type, dsl=nil)
|
7
|
+
@rel_type = rel_type
|
8
|
+
@relationships = []
|
9
|
+
@dsl = dsl
|
10
|
+
end
|
11
|
+
|
12
|
+
def rel_type
|
13
|
+
(@dsl && @dsl.rel_type) || @rel_type
|
14
|
+
end
|
15
|
+
|
16
|
+
def direction
|
17
|
+
(@dsl && @dsl.direction) || :outgoing
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
"#{self.class} #{object_id} dir: #{direction} rel_type: #{@rel_type} wrapped #{@dsl}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def single_relationship(*)
|
25
|
+
@relationships.first
|
26
|
+
end
|
27
|
+
|
28
|
+
def each(&block)
|
29
|
+
# TODO direction
|
30
|
+
# TODO DRY
|
31
|
+
@relationships.each do |rel|
|
32
|
+
block.call rel.end_node
|
33
|
+
end
|
34
|
+
@dsl.each(&block) if @dsl
|
35
|
+
end
|
36
|
+
|
37
|
+
def each_node(node, direction, &block) #:nodoc:
|
38
|
+
# TODO direction
|
39
|
+
@relationships.each do |rel|
|
40
|
+
block.call rel.end_node
|
41
|
+
end
|
42
|
+
@dsl.each_node(node, direction, &block) if @dsl && node.persisted?
|
43
|
+
end
|
44
|
+
|
45
|
+
def del_rel(rel)
|
46
|
+
# TODO, we need to delete this when it is saved
|
47
|
+
@relationships.delete(rel)
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_relationship_to(from, to)
|
51
|
+
#rel_type = (@dsl && @dsl.rel_type) || @rel_type
|
52
|
+
#from, to = (@dsl && @dsl.incoming?) ? [to, from] : [from, to]
|
53
|
+
@relationships << Relationship.new(@rel_type, from, to, self)
|
54
|
+
end
|
55
|
+
|
56
|
+
def single_node(from)
|
57
|
+
if !@relationships.empty?
|
58
|
+
@relationships.first.end_node
|
59
|
+
else
|
60
|
+
@dsl.single_node(from) if @dsl && from.persisted?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def valid?
|
65
|
+
all_valid = true
|
66
|
+
!@relationships.each do |rel|
|
67
|
+
start_node = rel.start_node
|
68
|
+
end_node = rel.end_node
|
69
|
+
|
70
|
+
if !end_node.valid?
|
71
|
+
all_valid = false
|
72
|
+
start_node.errors[@rel_type.to_sym] ||= []
|
73
|
+
start_node.errors[@rel_type.to_sym] << end_node.errors
|
74
|
+
end
|
75
|
+
end
|
76
|
+
all_valid
|
77
|
+
end
|
78
|
+
|
79
|
+
def persist
|
80
|
+
@relationships.each do |rel|
|
81
|
+
if @dsl
|
82
|
+
start_node = rel.start_node
|
83
|
+
end_node = rel.end_node
|
84
|
+
|
85
|
+
end_node.save!
|
86
|
+
@dsl.create_relationship_to(start_node, end_node)
|
87
|
+
else
|
88
|
+
rel.end_node.save!
|
89
|
+
rel.start_node.outgoing(@rel_type) << rel.end_node
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
module Relationships
|
4
|
+
|
5
|
+
class Relationship
|
6
|
+
attr_reader :rel_type, :start_node, :end_node
|
7
|
+
|
8
|
+
|
9
|
+
def initialize(rel_type, start_node, end_node, decl)
|
10
|
+
@rel_type = rel_type
|
11
|
+
@start_node = start_node
|
12
|
+
@end_node = end_node
|
13
|
+
@decl = decl
|
14
|
+
end
|
15
|
+
|
16
|
+
def del
|
17
|
+
@decl.del_rel(self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def persist
|
21
|
+
@start_node._java
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"Rel [#{rel_type} start #{start_node} end #{end_node}]"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
module Relationships
|
4
|
+
|
5
|
+
# TODO, reuse for incoming relationships ?
|
6
|
+
class OutgoingRelationship
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(from_node, mapper)
|
10
|
+
@from_node = from_node
|
11
|
+
@mapper = mapper
|
12
|
+
end
|
13
|
+
|
14
|
+
def <<(other)
|
15
|
+
@mapper.create_relationship_to(@from_node, other)
|
16
|
+
end
|
17
|
+
|
18
|
+
def each(&block)
|
19
|
+
# TODO Direction
|
20
|
+
@mapper.each &block
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def write_changed_relationships
|
26
|
+
@relationships.each_value do |mapper|
|
27
|
+
mapper.persist
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid_relationships?
|
32
|
+
!@relationships.values.find {|mapper| !mapper.valid?}
|
33
|
+
end
|
34
|
+
|
35
|
+
def _decl_rels_for(type)
|
36
|
+
dsl = super
|
37
|
+
if false && persisted?
|
38
|
+
dsl
|
39
|
+
else
|
40
|
+
@relationships[type] ||= Mapper.new(type, dsl)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
def clear_relationships
|
46
|
+
@relationships = {}
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def outgoing(rel_type)
|
51
|
+
if persisted?
|
52
|
+
super
|
53
|
+
else
|
54
|
+
@relationships[rel_type] ||= Mapper.new(rel_type)
|
55
|
+
OutgoingRelationship.new(self, @relationships[rel_type])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
module Serialization
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
include ActiveModel::Serializers::Xml
|
8
|
+
|
9
|
+
# Patch for ActiveModel's XML serializer. There is a bug in the original where
|
10
|
+
# raw_value is used in the initializer and so demands always that the object being
|
11
|
+
# serialized is sent the attribute's name as a method call. This causes a problem
|
12
|
+
# for Neo4j properties that aren't declared and so don't have methods to call. Besides
|
13
|
+
# which it's not necessary to re-call to get the value again if it has already
|
14
|
+
# been passed.
|
15
|
+
class ActiveModel::Serializers::Xml::Serializer::Attribute
|
16
|
+
def initialize(name, serializable, raw_value=nil)
|
17
|
+
@name, @serializable = name, serializable
|
18
|
+
@value = raw_value || @serializable.send(name)
|
19
|
+
@type = compute_type
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Handle all the created_at, updated_at, created_on, updated_on type stuff.
|
2
|
+
module Neo4j
|
3
|
+
module Rails
|
4
|
+
module Timestamps
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
TIMESTAMP_PROPERTIES = [ :created_at, :created_on, :updated_at, :updated_on ]
|
8
|
+
|
9
|
+
def write_changed_attributes
|
10
|
+
update_timestamp
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def init_on_create(*args)
|
15
|
+
create_timestamp
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
# Set the timestamps for this model if timestamps is set to true in the config
|
20
|
+
# and the model is set up with the correct property name, e.g.:
|
21
|
+
#
|
22
|
+
# class Trackable < Neo4j::Rails::Model
|
23
|
+
# property :updated_at, :type => DateTime
|
24
|
+
# end
|
25
|
+
def update_timestamp
|
26
|
+
write_date_or_timestamp(:updated_at) if Neo4j::Config[:timestamps] && respond_to?(:updated_at)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set the timestamps for this model if timestamps is set to true in the config
|
30
|
+
# and the model is set up with the correct property name, e.g.:
|
31
|
+
#
|
32
|
+
# class Trackable < Neo4j::Rails::Model
|
33
|
+
# property :created_at, :type => DateTime
|
34
|
+
# end
|
35
|
+
def create_timestamp
|
36
|
+
write_date_or_timestamp(:created_at) if Neo4j::Config[:timestamps] && respond_to?(:created_at)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Write the timestamp as a Date, DateTime or Time depending on the property type
|
40
|
+
def write_date_or_timestamp(attribute)
|
41
|
+
value = case self.class._decl_props[attribute][:type].to_s
|
42
|
+
when "DateTime"
|
43
|
+
DateTime.now
|
44
|
+
when "Date"
|
45
|
+
Date.today
|
46
|
+
when "Time"
|
47
|
+
Time.now
|
48
|
+
end
|
49
|
+
|
50
|
+
send("#{attribute}=", value)
|
51
|
+
end
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
def property_setup(property, options)
|
55
|
+
super
|
56
|
+
|
57
|
+
# ensure there's always a type on the timestamp properties
|
58
|
+
if Neo4j::Config[:timestamps] && TIMESTAMP_PROPERTIES.include?(property)
|
59
|
+
_decl_props[property][:type] = Time
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
|
4
|
+
# This method is typically used in an Rails ActionController as a filter method.
|
5
|
+
# It will guarantee that an transaction is create before your action is called,
|
6
|
+
# and that the transaction is finished after your action is called.
|
7
|
+
#
|
8
|
+
# Example:
|
9
|
+
# class MyController < ActionController::Base
|
10
|
+
# around_filter Neo4j::Rails::Transaction, :only => [:edit, :delete]
|
11
|
+
# ...
|
12
|
+
# end
|
13
|
+
class Transaction
|
14
|
+
class << self
|
15
|
+
def new
|
16
|
+
finish if Thread.current[:neo4j_transaction]
|
17
|
+
Thread.current[:neo4j_transaction] = Neo4j::Transaction.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def current
|
21
|
+
Thread.current[:neo4j_transaction]
|
22
|
+
end
|
23
|
+
|
24
|
+
def running?
|
25
|
+
Thread.current[:neo4j_transaction] != nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def fail?
|
29
|
+
Thread.current[:neo4j_transaction_fail] != nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def fail
|
33
|
+
Thread.current[:neo4j_transaction_fail] = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def success
|
37
|
+
Thread.current[:neo4j_transaction_fail] = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def finish
|
41
|
+
tx = Thread.current[:neo4j_transaction]
|
42
|
+
tx.success unless fail?
|
43
|
+
tx.finish
|
44
|
+
Thread.current[:neo4j_transaction] = nil
|
45
|
+
Thread.current[:neo4j_transaction_fail] = nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def filter(*, &block)
|
49
|
+
run &block
|
50
|
+
end
|
51
|
+
|
52
|
+
def run
|
53
|
+
begin
|
54
|
+
new
|
55
|
+
ret = yield self
|
56
|
+
rescue
|
57
|
+
fail
|
58
|
+
raise
|
59
|
+
ensure
|
60
|
+
finish
|
61
|
+
end
|
62
|
+
ret
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
module TxMethods
|
4
|
+
def tx_methods(*methods)
|
5
|
+
methods.each do |method|
|
6
|
+
tx_method = "#{method}_in_tx"
|
7
|
+
send(:alias_method, tx_method, method)
|
8
|
+
send(:define_method, method) do |*args|
|
9
|
+
Neo4j::Rails::Transaction.running? ? send(tx_method, *args) : Neo4j::Rails::Transaction.run { send(tx_method, *args) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
module Validations
|
4
|
+
include ActiveModel::Validations
|
5
|
+
|
6
|
+
def read_attribute_for_validation(key)
|
7
|
+
respond_to?(key) ? send(key) : self[key]
|
8
|
+
end
|
9
|
+
|
10
|
+
# The validation process on save can be skipped by passing false. The regular Model#save method is
|
11
|
+
# replaced with this when the validations module is mixed in, which it is by default.
|
12
|
+
def save(options={})
|
13
|
+
perform_validations(options) ? super : false
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid?(context = nil)
|
17
|
+
context ||= (new_record? ? :create : :update)
|
18
|
+
output = super(context)
|
19
|
+
output_rels = valid_relationships?
|
20
|
+
errors.empty? && output && output_rels
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def perform_validations(options={})
|
25
|
+
perform_validation = case options
|
26
|
+
when Hash
|
27
|
+
options[:validate] != false
|
28
|
+
end
|
29
|
+
|
30
|
+
if perform_validation
|
31
|
+
valid?(options.is_a?(Hash) ? options[:context] : nil)
|
32
|
+
else
|
33
|
+
true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
module Validations
|
4
|
+
class NonNilValidator < ActiveModel::EachValidator
|
5
|
+
def validate_each(record, attribute, value)
|
6
|
+
record.errors.add(attribute, :nil, options.merge(:value => value)) if value.nil?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Rails
|
3
|
+
module Validations
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class UniquenessValidator < ActiveModel::EachValidator
|
7
|
+
def initialize(options)
|
8
|
+
super(options.reverse_merge(:case_sensitive => true))
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup(klass)
|
12
|
+
@attributes.each do |attribute|
|
13
|
+
if klass.index_type_for(attribute) != :exact
|
14
|
+
raise "Can't validate property #{attribute.inspect} on class #{klass} since there is no :exact lucene index on that property or the index declaration #{attribute} comes after the validation declaration in #{klass} (try to move it before the validation rules)"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def validate_each(record, attribute, value)
|
20
|
+
return if options[:allow_blank] && value.blank?
|
21
|
+
record.class.all("#{attribute}: \"#{value}\"").each do |rec|
|
22
|
+
if rec.id != record.id # it doesn't count if we find ourself!
|
23
|
+
record.errors.add(attribute, :taken, options.except(:case_sensitive, :scope).merge(:value => value))
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
def validates_uniqueness_of(*attr_names)
|
32
|
+
validates_with UniquenessValidator, _merge_attributes(attr_names)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|