neo4j 2.0.0.alpha.5-java → 2.0.0.alpha.6-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/CHANGELOG +12 -0
  2. data/Gemfile +0 -4
  3. data/README.rdoc +106 -62
  4. data/lib/neo4j.rb +7 -33
  5. data/lib/neo4j/performance.rb +43 -0
  6. data/lib/neo4j/rails/accept_id.rb +19 -18
  7. data/lib/neo4j/rails/attributes.rb +366 -120
  8. data/lib/neo4j/rails/finders.rb +41 -15
  9. data/lib/neo4j/rails/has_n.rb +203 -0
  10. data/lib/neo4j/rails/identity.rb +25 -0
  11. data/lib/neo4j/rails/model.rb +65 -242
  12. data/lib/neo4j/rails/nested_attributes.rb +108 -0
  13. data/lib/neo4j/rails/node_persistance.rb +56 -0
  14. data/lib/neo4j/rails/observer.rb +0 -2
  15. data/lib/neo4j/rails/persistence.rb +32 -154
  16. data/lib/neo4j/rails/rack_middleware.rb +26 -2
  17. data/lib/neo4j/rails/rails.rb +9 -6
  18. data/lib/neo4j/rails/railtie.rb +1 -2
  19. data/lib/neo4j/rails/relationship.rb +18 -125
  20. data/lib/neo4j/rails/relationship_persistence.rb +107 -0
  21. data/lib/neo4j/rails/relationships/node_dsl.rb +72 -44
  22. data/lib/neo4j/rails/relationships/relationships.rb +187 -59
  23. data/lib/neo4j/rails/relationships/rels_dsl.rb +18 -17
  24. data/lib/neo4j/rails/relationships/storage.rb +19 -17
  25. data/lib/neo4j/rails/timestamps.rb +53 -51
  26. data/lib/neo4j/rails/transaction.rb +9 -1
  27. data/lib/neo4j/rails/validations/uniqueness.rb +1 -1
  28. data/lib/neo4j/rails/versioning/versioning.rb +2 -2
  29. data/lib/neo4j/version.rb +1 -1
  30. data/lib/orm_adapter/adapters/neo4j.rb +47 -46
  31. data/neo4j.gemspec +1 -1
  32. metadata +10 -69
  33. data/lib/neo4j/algo/algo.rb +0 -294
  34. data/lib/neo4j/batch/batch.rb +0 -4
  35. data/lib/neo4j/batch/indexer.rb +0 -109
  36. data/lib/neo4j/batch/inserter.rb +0 -179
  37. data/lib/neo4j/batch/rule_inserter.rb +0 -24
  38. data/lib/neo4j/batch/rule_node.rb +0 -72
  39. data/lib/neo4j/config.rb +0 -177
  40. data/lib/neo4j/core_ext/class/inheritable_attributes.rb +0 -12
  41. data/lib/neo4j/core_ext/class/rewrite_inheritable_attributes.rb +0 -170
  42. data/lib/neo4j/database.rb +0 -158
  43. data/lib/neo4j/equal.rb +0 -21
  44. data/lib/neo4j/event_handler.rb +0 -263
  45. data/lib/neo4j/has_list/class_methods.rb +0 -11
  46. data/lib/neo4j/has_list/has_list.rb +0 -3
  47. data/lib/neo4j/has_list/mapping.rb +0 -133
  48. data/lib/neo4j/has_n/class_methods.rb +0 -119
  49. data/lib/neo4j/has_n/decl_relationship_dsl.rb +0 -246
  50. data/lib/neo4j/has_n/has_n.rb +0 -3
  51. data/lib/neo4j/has_n/mapping.rb +0 -98
  52. data/lib/neo4j/identity_map.rb +0 -140
  53. data/lib/neo4j/index/class_methods.rb +0 -108
  54. data/lib/neo4j/index/index.rb +0 -39
  55. data/lib/neo4j/index/indexer.rb +0 -341
  56. data/lib/neo4j/index/indexer_registry.rb +0 -68
  57. data/lib/neo4j/index/lucene_query.rb +0 -256
  58. data/lib/neo4j/load.rb +0 -25
  59. data/lib/neo4j/migrations/class_methods.rb +0 -110
  60. data/lib/neo4j/migrations/extensions.rb +0 -58
  61. data/lib/neo4j/migrations/lazy_node_mixin.rb +0 -41
  62. data/lib/neo4j/migrations/migration.rb +0 -112
  63. data/lib/neo4j/migrations/migrations.rb +0 -6
  64. data/lib/neo4j/migrations/node_mixin.rb +0 -80
  65. data/lib/neo4j/migrations/ref_node_wrapper.rb +0 -32
  66. data/lib/neo4j/model.rb +0 -4
  67. data/lib/neo4j/neo4j.rb +0 -216
  68. data/lib/neo4j/node.rb +0 -270
  69. data/lib/neo4j/node_mixin/class_methods.rb +0 -51
  70. data/lib/neo4j/node_mixin/node_mixin.rb +0 -141
  71. data/lib/neo4j/paginated.rb +0 -23
  72. data/lib/neo4j/property/class_methods.rb +0 -79
  73. data/lib/neo4j/property/property.rb +0 -111
  74. data/lib/neo4j/rails/mapping/property.rb +0 -183
  75. data/lib/neo4j/rails/rel_persistence.rb +0 -237
  76. data/lib/neo4j/relationship.rb +0 -239
  77. data/lib/neo4j/relationship_mixin/class_methods.rb +0 -36
  78. data/lib/neo4j/relationship_mixin/relationship_mixin.rb +0 -142
  79. data/lib/neo4j/relationship_set.rb +0 -58
  80. data/lib/neo4j/rels/rels.rb +0 -110
  81. data/lib/neo4j/rels/traverser.rb +0 -102
  82. data/lib/neo4j/rule/class_methods.rb +0 -201
  83. data/lib/neo4j/rule/event_listener.rb +0 -66
  84. data/lib/neo4j/rule/functions/count.rb +0 -43
  85. data/lib/neo4j/rule/functions/function.rb +0 -74
  86. data/lib/neo4j/rule/functions/functions.rb +0 -3
  87. data/lib/neo4j/rule/functions/sum.rb +0 -29
  88. data/lib/neo4j/rule/rule.rb +0 -150
  89. data/lib/neo4j/rule/rule_node.rb +0 -217
  90. data/lib/neo4j/to_java.rb +0 -31
  91. data/lib/neo4j/transaction.rb +0 -73
  92. data/lib/neo4j/traversal/filter_predicate.rb +0 -25
  93. data/lib/neo4j/traversal/prune_evaluator.rb +0 -14
  94. data/lib/neo4j/traversal/rel_expander.rb +0 -31
  95. data/lib/neo4j/traversal/traversal.rb +0 -141
  96. data/lib/neo4j/traversal/traverser.rb +0 -284
  97. data/lib/neo4j/type_converters/type_converters.rb +0 -288
@@ -1,3 +0,0 @@
1
- require 'neo4j/has_n/class_methods'
2
- require 'neo4j/has_n/decl_relationship_dsl'
3
- require 'neo4j/has_n/mapping'
@@ -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
@@ -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
@@ -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
@@ -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