neo4j 2.0.0.alpha.5-java → 2.0.0.alpha.6-java
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/CHANGELOG +12 -0
- data/Gemfile +0 -4
- data/README.rdoc +106 -62
- data/lib/neo4j.rb +7 -33
- data/lib/neo4j/performance.rb +43 -0
- data/lib/neo4j/rails/accept_id.rb +19 -18
- data/lib/neo4j/rails/attributes.rb +366 -120
- data/lib/neo4j/rails/finders.rb +41 -15
- data/lib/neo4j/rails/has_n.rb +203 -0
- data/lib/neo4j/rails/identity.rb +25 -0
- data/lib/neo4j/rails/model.rb +65 -242
- data/lib/neo4j/rails/nested_attributes.rb +108 -0
- data/lib/neo4j/rails/node_persistance.rb +56 -0
- data/lib/neo4j/rails/observer.rb +0 -2
- data/lib/neo4j/rails/persistence.rb +32 -154
- data/lib/neo4j/rails/rack_middleware.rb +26 -2
- data/lib/neo4j/rails/rails.rb +9 -6
- data/lib/neo4j/rails/railtie.rb +1 -2
- data/lib/neo4j/rails/relationship.rb +18 -125
- data/lib/neo4j/rails/relationship_persistence.rb +107 -0
- data/lib/neo4j/rails/relationships/node_dsl.rb +72 -44
- data/lib/neo4j/rails/relationships/relationships.rb +187 -59
- data/lib/neo4j/rails/relationships/rels_dsl.rb +18 -17
- data/lib/neo4j/rails/relationships/storage.rb +19 -17
- data/lib/neo4j/rails/timestamps.rb +53 -51
- data/lib/neo4j/rails/transaction.rb +9 -1
- data/lib/neo4j/rails/validations/uniqueness.rb +1 -1
- data/lib/neo4j/rails/versioning/versioning.rb +2 -2
- data/lib/neo4j/version.rb +1 -1
- data/lib/orm_adapter/adapters/neo4j.rb +47 -46
- data/neo4j.gemspec +1 -1
- metadata +10 -69
- data/lib/neo4j/algo/algo.rb +0 -294
- data/lib/neo4j/batch/batch.rb +0 -4
- data/lib/neo4j/batch/indexer.rb +0 -109
- data/lib/neo4j/batch/inserter.rb +0 -179
- data/lib/neo4j/batch/rule_inserter.rb +0 -24
- data/lib/neo4j/batch/rule_node.rb +0 -72
- data/lib/neo4j/config.rb +0 -177
- data/lib/neo4j/core_ext/class/inheritable_attributes.rb +0 -12
- data/lib/neo4j/core_ext/class/rewrite_inheritable_attributes.rb +0 -170
- data/lib/neo4j/database.rb +0 -158
- data/lib/neo4j/equal.rb +0 -21
- data/lib/neo4j/event_handler.rb +0 -263
- data/lib/neo4j/has_list/class_methods.rb +0 -11
- data/lib/neo4j/has_list/has_list.rb +0 -3
- data/lib/neo4j/has_list/mapping.rb +0 -133
- data/lib/neo4j/has_n/class_methods.rb +0 -119
- data/lib/neo4j/has_n/decl_relationship_dsl.rb +0 -246
- data/lib/neo4j/has_n/has_n.rb +0 -3
- data/lib/neo4j/has_n/mapping.rb +0 -98
- data/lib/neo4j/identity_map.rb +0 -140
- data/lib/neo4j/index/class_methods.rb +0 -108
- data/lib/neo4j/index/index.rb +0 -39
- data/lib/neo4j/index/indexer.rb +0 -341
- data/lib/neo4j/index/indexer_registry.rb +0 -68
- data/lib/neo4j/index/lucene_query.rb +0 -256
- data/lib/neo4j/load.rb +0 -25
- data/lib/neo4j/migrations/class_methods.rb +0 -110
- data/lib/neo4j/migrations/extensions.rb +0 -58
- data/lib/neo4j/migrations/lazy_node_mixin.rb +0 -41
- data/lib/neo4j/migrations/migration.rb +0 -112
- data/lib/neo4j/migrations/migrations.rb +0 -6
- data/lib/neo4j/migrations/node_mixin.rb +0 -80
- data/lib/neo4j/migrations/ref_node_wrapper.rb +0 -32
- data/lib/neo4j/model.rb +0 -4
- data/lib/neo4j/neo4j.rb +0 -216
- data/lib/neo4j/node.rb +0 -270
- data/lib/neo4j/node_mixin/class_methods.rb +0 -51
- data/lib/neo4j/node_mixin/node_mixin.rb +0 -141
- data/lib/neo4j/paginated.rb +0 -23
- data/lib/neo4j/property/class_methods.rb +0 -79
- data/lib/neo4j/property/property.rb +0 -111
- data/lib/neo4j/rails/mapping/property.rb +0 -183
- data/lib/neo4j/rails/rel_persistence.rb +0 -237
- data/lib/neo4j/relationship.rb +0 -239
- data/lib/neo4j/relationship_mixin/class_methods.rb +0 -36
- data/lib/neo4j/relationship_mixin/relationship_mixin.rb +0 -142
- data/lib/neo4j/relationship_set.rb +0 -58
- data/lib/neo4j/rels/rels.rb +0 -110
- data/lib/neo4j/rels/traverser.rb +0 -102
- data/lib/neo4j/rule/class_methods.rb +0 -201
- data/lib/neo4j/rule/event_listener.rb +0 -66
- data/lib/neo4j/rule/functions/count.rb +0 -43
- data/lib/neo4j/rule/functions/function.rb +0 -74
- data/lib/neo4j/rule/functions/functions.rb +0 -3
- data/lib/neo4j/rule/functions/sum.rb +0 -29
- data/lib/neo4j/rule/rule.rb +0 -150
- data/lib/neo4j/rule/rule_node.rb +0 -217
- data/lib/neo4j/to_java.rb +0 -31
- data/lib/neo4j/transaction.rb +0 -73
- data/lib/neo4j/traversal/filter_predicate.rb +0 -25
- data/lib/neo4j/traversal/prune_evaluator.rb +0 -14
- data/lib/neo4j/traversal/rel_expander.rb +0 -31
- data/lib/neo4j/traversal/traversal.rb +0 -141
- data/lib/neo4j/traversal/traverser.rb +0 -284
- data/lib/neo4j/type_converters/type_converters.rb +0 -288
data/lib/neo4j/has_n/has_n.rb
DELETED
data/lib/neo4j/has_n/mapping.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
require 'neo4j/has_n/class_methods'
|
2
|
-
require 'neo4j/has_n/decl_relationship_dsl'
|
3
|
-
require 'neo4j/has_n/mapping'
|
4
|
-
|
5
|
-
module Neo4j
|
6
|
-
module HasN
|
7
|
-
|
8
|
-
# The object created by a has_n or has_one Neo4j::NodeMixin class method which enables creating and traversal of nodes.
|
9
|
-
#
|
10
|
-
# Includes the Enumerable mixin.
|
11
|
-
# The Neo4j::Mapping::ClassMethods::Relationship#has_n and Neo4j::Mapping::ClassMethods::Relationship#one
|
12
|
-
# methods returns an object of this type.
|
13
|
-
#
|
14
|
-
# ==== See Also
|
15
|
-
# Neo4j::HasN::ClassMethods
|
16
|
-
#
|
17
|
-
class Mapping
|
18
|
-
include Enumerable
|
19
|
-
include ToJava
|
20
|
-
|
21
|
-
def initialize(node, dsl) # :nodoc:
|
22
|
-
@node = node
|
23
|
-
@dsl = dsl
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_s
|
27
|
-
"HasN::Mapping [#{@dsl.dir}, id: #{@node.neo_id} type: #{@dsl && @dsl.rel_type} dsl:#{@dsl}]"
|
28
|
-
end
|
29
|
-
|
30
|
-
def size
|
31
|
-
self.to_a.size # TODO: Optimise this
|
32
|
-
end
|
33
|
-
|
34
|
-
alias_method :length, :size
|
35
|
-
|
36
|
-
|
37
|
-
def [](index)
|
38
|
-
i = 0
|
39
|
-
each{|x| return x if i == index; i += 1}
|
40
|
-
nil # out of index
|
41
|
-
end
|
42
|
-
|
43
|
-
# Pretend we are an array - this is necessarily for Rails actionpack/actionview/formhelper to work with this
|
44
|
-
def is_a?(type)
|
45
|
-
# ActionView requires this for nested attributes to work
|
46
|
-
return true if Array == type
|
47
|
-
super
|
48
|
-
end
|
49
|
-
|
50
|
-
# Required by the Enumerable mixin.
|
51
|
-
def each
|
52
|
-
@dsl.each_node(@node) {|n| yield n} # Should use yield here as passing &block through doesn't always work (why?)
|
53
|
-
end
|
54
|
-
|
55
|
-
# returns none wrapped nodes, you may get better performance using this method
|
56
|
-
def _each
|
57
|
-
@dsl._each_node(@node) {|n| yield n}
|
58
|
-
end
|
59
|
-
|
60
|
-
# Returns an real ruby array.
|
61
|
-
def to_ary
|
62
|
-
self.to_a
|
63
|
-
end
|
64
|
-
|
65
|
-
# Returns true if there are no node in this type of relationship
|
66
|
-
def empty?
|
67
|
-
first == nil
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
# Creates a relationship instance between this and the other node.
|
72
|
-
# Returns the relationship object
|
73
|
-
def new(other)
|
74
|
-
@dsl.create_relationship_to(@node, other)
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
# Creates a relationship between this and the other node.
|
79
|
-
#
|
80
|
-
# ==== Example
|
81
|
-
#
|
82
|
-
# n1 = Node.new # Node has declared having a friend type of relationship
|
83
|
-
# n2 = Node.new
|
84
|
-
# n3 = Node.new
|
85
|
-
#
|
86
|
-
# n1 << n2 << n3
|
87
|
-
#
|
88
|
-
# ==== Returns
|
89
|
-
# self
|
90
|
-
#
|
91
|
-
def <<(other)
|
92
|
-
@dsl.create_relationship_to(@node, other)
|
93
|
-
self
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
end
|
data/lib/neo4j/identity_map.rb
DELETED
@@ -1,140 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
|
3
|
-
# = Neo4j Identity Map
|
4
|
-
#
|
5
|
-
# Ensures that each object gets loaded only once by keeping every loaded
|
6
|
-
# object in a map. Looks up objects using the map when referring to them.
|
7
|
-
#
|
8
|
-
# More information on Identity Map pattern:
|
9
|
-
# http://www.martinfowler.com/eaaCatalog/identityMap.html
|
10
|
-
#
|
11
|
-
# == Configuration
|
12
|
-
#
|
13
|
-
# In order to enable IdentityMap, set <tt>config.neo4j.identity_map = true</tt>
|
14
|
-
# in your <tt>config/application.rb</tt> file. If used outside rails, set Neo4j::Config[:identity_map] = true.
|
15
|
-
#
|
16
|
-
# IdentityMap is disabled by default and still in development (i.e. use it with care).
|
17
|
-
#
|
18
|
-
module IdentityMap
|
19
|
-
|
20
|
-
class << self
|
21
|
-
def enabled=(flag)
|
22
|
-
Thread.current[:neo4j_identity_map] = flag
|
23
|
-
end
|
24
|
-
|
25
|
-
def enabled
|
26
|
-
Thread.current[:neo4j_identity_map]
|
27
|
-
end
|
28
|
-
|
29
|
-
alias enabled? enabled
|
30
|
-
|
31
|
-
def node_repository
|
32
|
-
Thread.current[:node_identity_map] ||= java.util.HashMap.new
|
33
|
-
end
|
34
|
-
|
35
|
-
def rel_repository
|
36
|
-
Thread.current[:rel_identity_map] ||= java.util.HashMap.new
|
37
|
-
end
|
38
|
-
|
39
|
-
def repository_for(neo_entity)
|
40
|
-
return nil unless enabled?
|
41
|
-
if neo_entity.class == Neo4j::Node
|
42
|
-
node_repository
|
43
|
-
elsif neo_entity.class == Neo4j::Relationship
|
44
|
-
rel_repository
|
45
|
-
else
|
46
|
-
nil
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def use
|
51
|
-
old, self.enabled = enabled, true
|
52
|
-
yield if block_given?
|
53
|
-
ensure
|
54
|
-
self.enabled = old
|
55
|
-
clear
|
56
|
-
end
|
57
|
-
|
58
|
-
def without
|
59
|
-
old, self.enabled = enabled, false
|
60
|
-
yield if block_given?
|
61
|
-
ensure
|
62
|
-
self.enabled = old
|
63
|
-
end
|
64
|
-
|
65
|
-
def get(neo_entity)
|
66
|
-
r = repository_for(neo_entity)
|
67
|
-
r && r.get(neo_entity.neo_id)
|
68
|
-
end
|
69
|
-
|
70
|
-
def add(neo_entity, wrapped_entity)
|
71
|
-
r = repository_for(neo_entity)
|
72
|
-
r && r.put(neo_entity.neo_id, wrapped_entity)
|
73
|
-
end
|
74
|
-
|
75
|
-
def remove(neo_entity)
|
76
|
-
r = repository_for(neo_entity)
|
77
|
-
r && r.remove(neo_entity.neo_id)
|
78
|
-
end
|
79
|
-
|
80
|
-
def remove_node_by_id(node_id)
|
81
|
-
node_repository.remove(node_id)
|
82
|
-
end
|
83
|
-
|
84
|
-
def remove_rel_by_id(rel_id)
|
85
|
-
rel_repository.remove(rel_id)
|
86
|
-
end
|
87
|
-
|
88
|
-
def clear
|
89
|
-
node_repository.clear
|
90
|
-
rel_repository.clear
|
91
|
-
end
|
92
|
-
|
93
|
-
def on_after_commit(*)
|
94
|
-
clear
|
95
|
-
end
|
96
|
-
|
97
|
-
def on_neo4j_started(db)
|
98
|
-
if not Neo4j::Config[:identity_map]
|
99
|
-
db.event_handler.remove(self)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
|
106
|
-
class Middleware
|
107
|
-
class Body #:nodoc:
|
108
|
-
def initialize(target, original)
|
109
|
-
@target = target
|
110
|
-
@original = original
|
111
|
-
end
|
112
|
-
|
113
|
-
def each(&block)
|
114
|
-
@target.each(&block)
|
115
|
-
end
|
116
|
-
|
117
|
-
def close
|
118
|
-
@target.close if @target.respond_to?(:close)
|
119
|
-
ensure
|
120
|
-
IdentityMap.enabled = @original
|
121
|
-
IdentityMap.clear
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def initialize(app)
|
126
|
-
@app = app
|
127
|
-
end
|
128
|
-
|
129
|
-
def call(env)
|
130
|
-
enabled = IdentityMap.enabled
|
131
|
-
IdentityMap.enabled = Neo4j::Config[:identity_map]
|
132
|
-
status, headers, body = @app.call(env)
|
133
|
-
[status, headers, Body.new(body, enabled)]
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
Neo4j.unstarted_db.event_handler.add(Neo4j::IdentityMap)
|
140
|
-
|
@@ -1,108 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
module Index
|
3
|
-
module ClassMethods
|
4
|
-
attr_reader :_indexer
|
5
|
-
|
6
|
-
extend Forwardable
|
7
|
-
|
8
|
-
def wp_query(options, pager, args, &block) #:nodoc:
|
9
|
-
params = {}
|
10
|
-
params[:page] = pager.current_page
|
11
|
-
params[:per_page] = pager.per_page
|
12
|
-
query = if args.empty?
|
13
|
-
find(options, params, &block)
|
14
|
-
else
|
15
|
-
args << params.merge(options)
|
16
|
-
find(*args, &block)
|
17
|
-
end
|
18
|
-
|
19
|
-
pager.replace [*query]
|
20
|
-
pager.total_entries = query.size
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
##
|
25
|
-
# See Neo4j::Index::Indexer#index
|
26
|
-
# Forwards to the indexer that should be used.
|
27
|
-
# It is possible to share the same index for several different classes, see #node_indexer.
|
28
|
-
# :singleton-method: index
|
29
|
-
|
30
|
-
##
|
31
|
-
# See Neo4j::Index::Indexer#find
|
32
|
-
# Forwards to the indexer that should be used.
|
33
|
-
# It is possible to share the same index for several different classes, see #node_indexer.
|
34
|
-
# :singleton-method: find
|
35
|
-
|
36
|
-
##
|
37
|
-
# Specifies the location on the filesystem of the lucene index for the given index type.
|
38
|
-
#
|
39
|
-
# If not specified it will have the default location:
|
40
|
-
#
|
41
|
-
# Neo4j.config[:storage_path]/index/lucene/node|relationship/ParentModuleName_SubModuleName_ClassName-indextype
|
42
|
-
#
|
43
|
-
# Forwards to the Indexer#index_names class
|
44
|
-
#
|
45
|
-
# ==== Example
|
46
|
-
# module Foo
|
47
|
-
# class Person
|
48
|
-
# include Neo4j::NodeMixin
|
49
|
-
# index :name
|
50
|
-
# index_names[:fulltext] = 'my_location'
|
51
|
-
# end
|
52
|
-
# end
|
53
|
-
#
|
54
|
-
# Person.index_names[:fulltext] => 'my_location'
|
55
|
-
# Person.index_names[:exact] => 'Foo_Person-exact' # default Location
|
56
|
-
#
|
57
|
-
# The index can be prefixed, see Neo4j#threadlocal_ref_node= and multi dendency.
|
58
|
-
#
|
59
|
-
# :singleton-method: index_names
|
60
|
-
|
61
|
-
|
62
|
-
##
|
63
|
-
# Returns a hash of which indexes has been defined and the type of index (:exact or :fulltext)
|
64
|
-
#
|
65
|
-
# :singleton-method: index_types
|
66
|
-
|
67
|
-
|
68
|
-
def_delegators :@_indexer, :index, :find, :index?, :index_type?, :delete_index_type, :rm_field_type, :add_index, :rm_index, :index_type_for, :index_names, :index_types
|
69
|
-
|
70
|
-
# Sets which indexer should be used for the given node class.
|
71
|
-
# You can share an indexer between several different classes.
|
72
|
-
#
|
73
|
-
# ==== Example
|
74
|
-
# class Contact
|
75
|
-
# include Neo4j::NodeMixin
|
76
|
-
# index :name
|
77
|
-
# has_one :phone
|
78
|
-
# end
|
79
|
-
#
|
80
|
-
# class Phone
|
81
|
-
# include Neo4j::NodeMixin
|
82
|
-
# property :phone
|
83
|
-
# node_indexer Contact # put index on the Contact class instead
|
84
|
-
# index :phone
|
85
|
-
# end
|
86
|
-
#
|
87
|
-
# # Find an contact with a phone number, this works since they share the same index
|
88
|
-
# Contact.find('phone: 12345').first #=> a phone object !
|
89
|
-
#
|
90
|
-
# ==== Returns
|
91
|
-
# The indexer that should be used to index the given class
|
92
|
-
def node_indexer(clazz)
|
93
|
-
indexer(clazz, :node)
|
94
|
-
end
|
95
|
-
|
96
|
-
# Sets which indexer should be used for the given relationship class
|
97
|
-
# Same as #node_indexer except that it indexes relationships instead of nodes.
|
98
|
-
#
|
99
|
-
def rel_indexer(clazz)
|
100
|
-
indexer(clazz, :rel)
|
101
|
-
end
|
102
|
-
|
103
|
-
def indexer(clazz, type) #:nodoc:
|
104
|
-
@_indexer ||= IndexerRegistry.create_for(self, clazz, type)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
data/lib/neo4j/index/index.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'neo4j/index/class_methods'
|
2
|
-
require 'neo4j/index/indexer_registry'
|
3
|
-
require 'neo4j/index/indexer'
|
4
|
-
require 'neo4j/index/lucene_query'
|
5
|
-
|
6
|
-
module Neo4j
|
7
|
-
|
8
|
-
module Index
|
9
|
-
|
10
|
-
# Adds an index on the given property
|
11
|
-
# Notice that you normally don't have to do that since you simply can declare
|
12
|
-
# that the property and index should be updated automatically by using the class method #index.
|
13
|
-
#
|
14
|
-
# The index operation will take place immediately unlike when using the Neo4j::Index::ClassMethods::index
|
15
|
-
# method which instead will guarantee that the neo4j database and the lucene database will be consistent.
|
16
|
-
# It uses a two phase commit when the transaction is about to be committed.
|
17
|
-
#
|
18
|
-
# ==== See also
|
19
|
-
# Neo4j::Index::ClassMethods::index
|
20
|
-
#
|
21
|
-
def add_index(field, value=self[field])
|
22
|
-
converted_value = Neo4j::TypeConverters.convert(value, field, self.class)
|
23
|
-
self.class.add_index(wrapped_entity, field.to_s, converted_value)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Removes an index on the given property.
|
27
|
-
# Just like #add_index this is normally not needed since you instead can declare it with the
|
28
|
-
# #index class method instead.
|
29
|
-
#
|
30
|
-
# ==== See also
|
31
|
-
# Neo4j::Index::ClassMethods::index
|
32
|
-
# Neo4j::Index#add_index
|
33
|
-
#
|
34
|
-
def rm_index(field, value=self[field])
|
35
|
-
self.class.rm_index(wrapped_entity, field.to_s, value)
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
data/lib/neo4j/index/indexer.rb
DELETED
@@ -1,341 +0,0 @@
|
|
1
|
-
module Neo4j
|
2
|
-
module Index
|
3
|
-
class Indexer
|
4
|
-
attr_reader :indexer_for, :field_types, :via_relationships, :entity_type, :parent_indexers, :via_relationships
|
5
|
-
alias_method :index_types, :field_types # public method accessible from node.index_types
|
6
|
-
|
7
|
-
def initialize(clazz, type) #:nodoc:
|
8
|
-
# part of the unique name of the index
|
9
|
-
@indexer_for = clazz
|
10
|
-
|
11
|
-
# do we want to index nodes or relationships ?
|
12
|
-
@entity_type = type
|
13
|
-
|
14
|
-
@indexes = {} # key = type, value = java neo4j index
|
15
|
-
@field_types = {} # key = field, value = type (e.g. :exact or :fulltext)
|
16
|
-
@via_relationships = {} # key = field, value = relationship
|
17
|
-
|
18
|
-
# to enable subclass indexing to work properly, store a list of parent indexers and
|
19
|
-
# whenever an operation is performed on this one, perform it on all
|
20
|
-
@parent_indexers = []
|
21
|
-
end
|
22
|
-
|
23
|
-
def inherit_fields_from(parent_index) #:nodoc:
|
24
|
-
return unless parent_index
|
25
|
-
@field_types.reverse_merge!(parent_index.field_types) if parent_index.respond_to?(:field_types)
|
26
|
-
@via_relationships.reverse_merge!(parent_index.via_relationships) if parent_index.respond_to?(:via_relationships)
|
27
|
-
@parent_indexers << parent_index
|
28
|
-
end
|
29
|
-
|
30
|
-
def to_s
|
31
|
-
"Indexer @#{object_id} [index_for:#{@indexer_for}, field_types=#{@field_types.keys.join(', ')}, via=#{@via_relationships.inspect}]"
|
32
|
-
end
|
33
|
-
|
34
|
-
# Add an index on a field so that it will be automatically updated by neo4j transactional events.
|
35
|
-
#
|
36
|
-
# The index method takes an optional configuration hash which allows you to:
|
37
|
-
#
|
38
|
-
# === Add an index on an a property
|
39
|
-
#
|
40
|
-
# Example:
|
41
|
-
# class Person
|
42
|
-
# include Neo4j::NodeMixin
|
43
|
-
# index :name
|
44
|
-
# end
|
45
|
-
#
|
46
|
-
# When the property name is changed/deleted or the node created it will keep the lucene index in sync.
|
47
|
-
# You can then perform a lucene query like this: Person.find('name: andreas')
|
48
|
-
#'
|
49
|
-
# === Add index on other nodes.
|
50
|
-
#
|
51
|
-
# Example:
|
52
|
-
#
|
53
|
-
# class Person
|
54
|
-
# include Neo4j::NodeMixin
|
55
|
-
# has_n(:friends).to(Contact)
|
56
|
-
# has_n(:known_by).from(:friends)
|
57
|
-
# index :user_id, :via => :known_by
|
58
|
-
# end
|
59
|
-
#
|
60
|
-
# Notice that you *must* specify an incoming relationship with the via key, as shown above.
|
61
|
-
# In the example above an index <tt>user_id</tt> will be added to all Person nodes which has a <tt>friends</tt> relationship
|
62
|
-
# that person with that user_id. This allows you to do lucene queries on your friends properties.
|
63
|
-
#
|
64
|
-
# === Set the type value to index
|
65
|
-
# By default all values will be indexed as Strings.
|
66
|
-
# If you want for example to do a numerical range query you must tell Neo4j.rb to index it as a numeric value.
|
67
|
-
# You do that with the key <tt>type</tt> on the property.
|
68
|
-
#
|
69
|
-
# Example:
|
70
|
-
# class Person
|
71
|
-
# include Neo4j::NodeMixin
|
72
|
-
# property :height, :weight, :type => Float
|
73
|
-
# index :height, :weight
|
74
|
-
# end
|
75
|
-
#
|
76
|
-
# Supported values for <tt>:type</tt> is <tt>String</tt>, <tt>Float</tt>, <tt>Date</tt>, <tt>DateTime</tt> and <tt>Fixnum</tt>
|
77
|
-
#
|
78
|
-
# === For more information
|
79
|
-
# * See Neo4j::Index::LuceneQuery
|
80
|
-
# * See #find
|
81
|
-
#
|
82
|
-
def index(*args)
|
83
|
-
conf = args.last.kind_of?(Hash) ? args.pop : {}
|
84
|
-
conf_no_via = conf.reject { |k,v| k == :via } # avoid endless recursion
|
85
|
-
|
86
|
-
args.uniq.each do | field |
|
87
|
-
if conf[:via]
|
88
|
-
rel_dsl = @indexer_for._decl_rels[conf[:via]]
|
89
|
-
raise "No relationship defined for '#{conf[:via]}'. Check class '#{@indexer_for}': index :#{field}, via=>:#{conf[:via]} <-- error. Define it with a has_one or has_n" unless rel_dsl
|
90
|
-
raise "Only incoming relationship are possible to define index on. Check class '#{@indexer_for}': index :#{field}, via=>:#{conf[:via]}" unless rel_dsl.incoming?
|
91
|
-
via_indexer = rel_dsl.target_class._indexer
|
92
|
-
|
93
|
-
field = field.to_s
|
94
|
-
@via_relationships[field] = rel_dsl
|
95
|
-
via_indexer.index(field, conf_no_via)
|
96
|
-
else
|
97
|
-
@field_types[field.to_s] = conf[:type] || :exact
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def remove_index_on_fields(node, props, deleted_relationship_set) #:nodoc:
|
103
|
-
@field_types.keys.each { |field| rm_index(node, field, props[field]) if props[field] }
|
104
|
-
# remove all via indexed fields
|
105
|
-
@via_relationships.each_value do |dsl|
|
106
|
-
indexer = dsl.target_class._indexer
|
107
|
-
deleted_relationship_set.relationships(node.getId).each do |rel|
|
108
|
-
indexer.remove_index_on_fields(rel._start_node, props, deleted_relationship_set)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def update_on_deleted_relationship(relationship) #:nodoc:
|
114
|
-
update_on_relationship(relationship, false)
|
115
|
-
end
|
116
|
-
|
117
|
-
def update_on_new_relationship(relationship) #:nodoc:
|
118
|
-
update_on_relationship(relationship, true)
|
119
|
-
end
|
120
|
-
|
121
|
-
def update_on_relationship(relationship, is_created) #:nodoc:
|
122
|
-
rel_type = relationship.rel_type
|
123
|
-
end_node = relationship._end_node
|
124
|
-
# find which via relationship match rel_type
|
125
|
-
@via_relationships.each_pair do |field, dsl|
|
126
|
-
# have we declared an index on this changed relationship ?
|
127
|
-
next unless dsl.rel_type == rel_type
|
128
|
-
|
129
|
-
# yes, so find the node and value we should update the index on
|
130
|
-
val = end_node[field]
|
131
|
-
start_node = relationship._start_node
|
132
|
-
|
133
|
-
# find the indexer to use
|
134
|
-
indexer = dsl.target_class._indexer
|
135
|
-
|
136
|
-
# is the relationship created or deleted ?
|
137
|
-
if is_created
|
138
|
-
indexer.update_index_on(start_node, field, nil, val)
|
139
|
-
else
|
140
|
-
indexer.update_index_on(start_node, field, val, nil)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def update_index_on(node, field, old_val, new_val) #:nodoc:
|
146
|
-
if @via_relationships.include?(field)
|
147
|
-
dsl = @via_relationships[field]
|
148
|
-
target_class = dsl.target_class
|
149
|
-
|
150
|
-
dsl._all_relationships(node).each do |rel|
|
151
|
-
other = rel._start_node
|
152
|
-
target_class._indexer.update_single_index_on(other, field, old_val, new_val)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
update_single_index_on(node, field, old_val, new_val)
|
156
|
-
end
|
157
|
-
|
158
|
-
def update_single_index_on(node, field, old_val, new_val) #:nodoc:
|
159
|
-
if @field_types.has_key?(field)
|
160
|
-
rm_index(node, field, old_val) if old_val
|
161
|
-
add_index(node, field, new_val) if new_val
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
# Returns true if there is an index on the given field.
|
166
|
-
#
|
167
|
-
def index?(field)
|
168
|
-
@field_types.include?(field.to_s)
|
169
|
-
end
|
170
|
-
|
171
|
-
# Returns the type of index for the given field (e.g. :exact or :fulltext)
|
172
|
-
#
|
173
|
-
def index_type_for(field) #:nodoc:
|
174
|
-
return nil unless index?(field)
|
175
|
-
@field_types[field.to_s]
|
176
|
-
end
|
177
|
-
|
178
|
-
# Returns true if there is an index of the given type defined.
|
179
|
-
def index_type?(type)
|
180
|
-
@field_types.values.include?(type)
|
181
|
-
end
|
182
|
-
|
183
|
-
# Adds an index on the given entity
|
184
|
-
# This is normally not needed since you can instead declare an index which will automatically keep
|
185
|
-
# the lucene index in sync. See #index
|
186
|
-
#
|
187
|
-
def add_index(entity, field, value)
|
188
|
-
return false unless @field_types.has_key?(field)
|
189
|
-
conv_value = indexed_value_for(field, value)
|
190
|
-
index = index_for_field(field.to_s)
|
191
|
-
index.add(entity, field, conv_value)
|
192
|
-
@parent_indexers.each { |i| i.add_index(entity, field, value) }
|
193
|
-
end
|
194
|
-
|
195
|
-
def indexed_value_for(field, value)
|
196
|
-
# we might need to know what type the properties are when indexing and querying
|
197
|
-
@decl_props ||= @indexer_for.respond_to?(:_decl_props) && @indexer_for._decl_props
|
198
|
-
|
199
|
-
type = @decl_props && @decl_props[field.to_sym] && @decl_props[field.to_sym][:type]
|
200
|
-
return value unless type
|
201
|
-
|
202
|
-
if String != type
|
203
|
-
org.neo4j.index.lucene.ValueContext.new(value).indexNumeric
|
204
|
-
else
|
205
|
-
org.neo4j.index.lucene.ValueContext.new(value)
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
# Removes an index on the given entity
|
210
|
-
# This is normally not needed since you can instead declare an index which will automatically keep
|
211
|
-
# the lucene index in sync. See #index
|
212
|
-
#
|
213
|
-
def rm_index(entity, field, value)
|
214
|
-
return false unless @field_types.has_key?(field)
|
215
|
-
index_for_field(field).remove(entity, field, value)
|
216
|
-
@parent_indexers.each { |i| i.rm_index(entity, field, value) }
|
217
|
-
end
|
218
|
-
|
219
|
-
# Performs a Lucene Query.
|
220
|
-
#
|
221
|
-
# In order to use this you have to declare an index on the fields first, see #index.
|
222
|
-
# Notice that you should close the lucene query after the query has been executed.
|
223
|
-
# You can do that either by provide an block or calling the Neo4j::Index::LuceneQuery#close
|
224
|
-
# method. When performing queries from Ruby on Rails you do not need this since it will be automatically closed
|
225
|
-
# (by Rack).
|
226
|
-
#
|
227
|
-
# === Example, with a block
|
228
|
-
#
|
229
|
-
# Person.find('name: kalle') {|query| puts "#{[*query].join(', )"}
|
230
|
-
#
|
231
|
-
# ==== Example
|
232
|
-
#
|
233
|
-
# query = Person.find('name: kalle')
|
234
|
-
# puts "First item #{query.first}"
|
235
|
-
# query.close
|
236
|
-
#
|
237
|
-
# === Return Value
|
238
|
-
# It will return a Neo4j::Index::LuceneQuery object
|
239
|
-
#
|
240
|
-
#
|
241
|
-
def find(query, params = {})
|
242
|
-
# we might need to know what type the properties are when indexing and querying
|
243
|
-
@decl_props ||= @indexer_for.respond_to?(:_decl_props) && @indexer_for._decl_props
|
244
|
-
|
245
|
-
index = index_for_type(params[:type] || :exact)
|
246
|
-
if query.is_a?(Hash) && (query.include?(:conditions) || query.include?(:sort))
|
247
|
-
params.merge! query.except(:conditions)
|
248
|
-
query.delete(:sort)
|
249
|
-
query = query.delete(:conditions) if query.include?(:conditions)
|
250
|
-
end
|
251
|
-
query = (params[:wrapped].nil? || params[:wrapped]) ? LuceneQuery.new(index, @decl_props, query, params) : index.query(query)
|
252
|
-
|
253
|
-
if block_given?
|
254
|
-
begin
|
255
|
-
ret = yield query
|
256
|
-
ensure
|
257
|
-
query.close
|
258
|
-
end
|
259
|
-
ret
|
260
|
-
else
|
261
|
-
query
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
# delete the index, if no type is provided clear all types of indexes
|
266
|
-
def delete_index_type(type=nil)
|
267
|
-
if type
|
268
|
-
#raise "can't clear index of type '#{type}' since it does not exist ([#{@field_types.values.join(',')}] exists)" unless index_type?(type)
|
269
|
-
key = index_key(type)
|
270
|
-
@indexes[key] && @indexes[key].delete
|
271
|
-
@indexes[key] = nil
|
272
|
-
else
|
273
|
-
@indexes.each_value { |index| index.delete }
|
274
|
-
@indexes.clear
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
def on_neo4j_shutdown #:nodoc:
|
279
|
-
# Since we might start the database again we must make sure that we don't keep any references to
|
280
|
-
# an old lucene index in memory.
|
281
|
-
@indexes.clear
|
282
|
-
end
|
283
|
-
|
284
|
-
# Removes the cached lucene index, can be useful for some RSpecs which needs to restart the Neo4j.
|
285
|
-
#
|
286
|
-
def rm_field_type(type=nil)
|
287
|
-
if type
|
288
|
-
@field_types.delete_if { |k, v| v == type }
|
289
|
-
else
|
290
|
-
@field_types.clear
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
def index_for_field(field) #:nodoc:
|
295
|
-
type = @field_types[field]
|
296
|
-
@indexes[index_key(type)] ||= create_index_with(type)
|
297
|
-
end
|
298
|
-
|
299
|
-
def index_for_type(type) #:nodoc:
|
300
|
-
@indexes[index_key(type)] ||= create_index_with(type)
|
301
|
-
end
|
302
|
-
|
303
|
-
def index_key(type)
|
304
|
-
index_names[type] + type.to_s
|
305
|
-
end
|
306
|
-
|
307
|
-
def lucene_config(type) #:nodoc:
|
308
|
-
conf = Neo4j::Config[:lucene][type.to_sym]
|
309
|
-
raise "unknown lucene type #{type}" unless conf
|
310
|
-
conf
|
311
|
-
end
|
312
|
-
|
313
|
-
def create_index_with(type) #:nodoc:
|
314
|
-
db = Neo4j.started_db
|
315
|
-
index_config = lucene_config(type)
|
316
|
-
if @entity_type == :node
|
317
|
-
db.lucene.for_nodes(index_names[type], index_config)
|
318
|
-
else
|
319
|
-
db.lucene.for_relationships(index_names[type], index_config)
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
def index_names
|
324
|
-
@index_names ||= Hash.new do |hash, index_type|
|
325
|
-
default_filename = index_prefix + @indexer_for.to_s.gsub('::', '_')
|
326
|
-
hash.fetch(index_type) {"#{default_filename}_#{index_type}"}
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
protected
|
331
|
-
def index_prefix
|
332
|
-
return "" unless Neo4j.running?
|
333
|
-
return "" unless @indexer_for.respond_to?(:ref_node_for_class)
|
334
|
-
ref_node = @indexer_for.ref_node_for_class.wrapper
|
335
|
-
prefix = ref_node.send(:_index_prefix) if ref_node.respond_to?(:_index_prefix)
|
336
|
-
prefix ||= ref_node[:name] # To maintain backward compatiblity
|
337
|
-
prefix.blank? ? "" : prefix + "_"
|
338
|
-
end
|
339
|
-
end
|
340
|
-
end
|
341
|
-
end
|