neo4j 1.0.0.beta.18 → 1.0.0.beta.19

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/lib/neo4j.rb CHANGED
@@ -5,11 +5,11 @@ require 'forwardable'
5
5
  require 'time'
6
6
  require 'date'
7
7
 
8
- require 'neo4j/jars/neo4j-index-1.2-1.2.M02.jar'
9
- require 'neo4j/jars/neo4j-kernel-1.2-1.2.M02.jar'
10
- require 'neo4j/jars/neo4j-lucene-index-0.2-1.2.M02.jar'
8
+ require 'neo4j/jars/neo4j-index-1.2-1.2.M03.jar'
9
+ require 'neo4j/jars/neo4j-kernel-1.2-1.2.M03.jar'
10
+ require 'neo4j/jars/neo4j-lucene-index-0.2-1.2.M03.jar'
11
11
  require 'neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar'
12
- require 'neo4j/jars/lucene-core-3.0.1.jar'
12
+ require 'neo4j/jars/lucene-core-3.0.2.jar'
13
13
  require 'neo4j/to_java'
14
14
  require 'neo4j/version'
15
15
  require 'neo4j/equal'
@@ -32,6 +32,7 @@ require 'neo4j/load'
32
32
  require 'neo4j/relationship'
33
33
  require 'neo4j/node'
34
34
  require 'neo4j/config'
35
+ require 'neo4j/type_converters'
35
36
  require 'neo4j/mapping/class_methods/init_node'
36
37
  require 'neo4j/mapping/class_methods/init_rel'
37
38
  require 'neo4j/mapping/class_methods/root'
data/lib/neo4j/config.rb CHANGED
@@ -2,13 +2,19 @@
2
2
  module Neo4j
3
3
 
4
4
 
5
- # == Keeps configuration for neo4j.
5
+ # == Keeps configuration for neo4j
6
6
  #
7
7
  # The most important configuration is <tt>Neo4j::Config[:storage_path]</tt> which is used to
8
8
  # locate where the neo4j database is stored on the filesystem.
9
9
  # If this directory is empty then a new database will be created, otherwise it will use the
10
10
  # database from that directory.
11
11
  #
12
+ # ==== Default Configurations
13
+ # <tt>:storage_path</tt>:: default <tt>tmp/neo4j</tt> where the database is stored
14
+ # <tt>:timestamps</tt>:: default <tt>true</tt> for Rails Neo4j::Model - if timestamps should be used when saving the model
15
+ # <tt>:lucene</tt>:: default hash keys: <tt>:fulltext</tt>, <tt>:exact</tt> configuration how the lucene index is stored
16
+ # <tt>:converters</tt>:: defines which converters should be used before writing and reading to neo4j, see Neo4j::TypeConverters
17
+ #
12
18
  class Config
13
19
  # This code is copied from merb-core/config.rb.
14
20
  class << self
@@ -19,6 +25,7 @@ module Neo4j
19
25
  def defaults
20
26
  @defaults ||= {
21
27
  :storage_path => 'tmp/neo4j',
28
+ :timestamps => true,
22
29
  :lucene => {
23
30
  :fulltext => {"provider" => "lucene", "type" => "fulltext" },
24
31
  :exact => {"provider" => "lucene", "type" => "exact" }}
@@ -29,11 +36,11 @@ module Neo4j
29
36
  # Yields the configuration.
30
37
  #
31
38
  # ==== Block parameters
32
- # c<Hash>:: The configuration parameters.
39
+ # c :: The configuration parameters, a hash.
33
40
  #
34
41
  # ==== Examples
35
42
  # Neo4j::Config.use do |config|
36
- # config[:storage_path] = '/var/neo4j'
43
+ # config[:storage_path] = '/var/neo4j'
37
44
  # end
38
45
  #
39
46
  # ==== Returns
@@ -48,8 +55,8 @@ module Neo4j
48
55
  # Set the value of a config entry.
49
56
  #
50
57
  # ==== Parameters
51
- # key:: The key to set the parameter for.
52
- # val:: The value of the parameter.
58
+ # key :: The key to set the parameter for.
59
+ # val :: The value of the parameter.
53
60
  #
54
61
  def []=(key, val)
55
62
  (@configuration ||= setup)[key] = val
@@ -63,15 +63,16 @@ module Neo4j
63
63
  # === Set the type value to index
64
64
  # By default all values will be indexed as Strings.
65
65
  # If you want for example to do a numerical range query you must tell Neo4j.rb to index it as a numeric value.
66
- # You do that with the key <tt>type</tt>
66
+ # You do that with the key <tt>type</tt> on the property.
67
67
  #
68
68
  # Example:
69
69
  # class Person
70
70
  # include Neo4j::NodeMixin
71
- # index :weight, :type => Float
71
+ # property :weight, :type => Float
72
+ # index :weight
72
73
  # end
73
74
  #
74
- # Supported values for <tt>:type</tt> is <tt>String</tt>, <tt>Float</tt> and <tt>Fixnum</tt>
75
+ # Supported values for <tt>:type</tt> is <tt>String</tt>, <tt>Float</tt>, <tt>Date</tt>, <tt>DateTime</tt> and <tt>Fixnum</tt>
75
76
  #
76
77
  # === For more information
77
78
  # * See Neo4j::Index::LuceneQuery
@@ -189,13 +190,11 @@ module Neo4j
189
190
 
190
191
  type = @decl_props && @decl_props[field.to_sym] && @decl_props[field.to_sym][:type]
191
192
  if type
192
- raise "Can't index #{type} with value #{value} since it is not a #{type}" unless type === value
193
193
  value = if String != type
194
194
  org.neo4j.index.impl.lucene.ValueContext.new(value).indexNumeric
195
195
  else
196
196
  org.neo4j.index.impl.lucene.ValueContext.new(value)
197
197
  end
198
-
199
198
  end
200
199
 
201
200
  index_for_field(field.to_s).add(entity, field, value)
@@ -45,64 +45,99 @@ module Neo4j
45
45
  @decl_props = decl_props
46
46
  end
47
47
 
48
+ # Since we include the Ruby Enumerable mixin we need this method.
48
49
  def each
49
50
  hits.each { |n| yield n.wrapper }
50
51
  end
51
52
 
53
+ # Close hits
54
+ #
55
+ # Closes the underlying search result. This method should be called whenever you've got what you wanted from the result and won't use it anymore.
56
+ # It's necessary to call it so that underlying indexes can dispose of allocated resources for this search result.
57
+ # You can however skip to call this method if you loop through the whole result, then close() will be called automatically.
58
+ # Even if you loop through the entire result and then call this method it will silently ignore any consequtive call (for convenience).
59
+ #
60
+ # This must be done according to the Neo4j Java Documentation:
52
61
  def close
53
62
  @hits.close if @hits
54
63
  end
55
64
 
65
+ # True if there is no search hits.
56
66
  def empty?
57
67
  hits.size == 0
58
68
  end
59
69
 
70
+ # returns the n'th search item
71
+ # Does simply loop all search items till the n'th is found.
72
+ #
60
73
  def [](index)
61
74
  each_with_index {|node,i| break node if index == i}
62
75
  end
63
76
 
77
+ # Returns the number of search hits
64
78
  def size
65
79
  hits.size
66
80
  end
67
81
 
68
- def hits
82
+ def hits #:nodoc:
69
83
  @hits ||= perform_query
70
84
  end
71
85
 
72
- def between(lower, upper)
86
+ # Performs a range query
87
+ # Notice that if you don't specify a type when declaring a property a String range query will be performed.
88
+ #
89
+ def between(lower, upper, lower_incusive=false, upper_inclusive=false)
73
90
  raise "Expected a symbol. Syntax for range queries example: index(:weight).between(a,b)" unless Symbol === @query
74
91
  raise "Can't only do range queries on Neo4j::NodeMixin, Neo4j::Model, Neo4j::RelationshipMixin" unless @decl_props
75
- type = @decl_props[@query] && @decl_props[@query][:type]
76
- raise "Missing type declaration of property #{@query}. E.g. property :#{@query}, :type => Float; index :#{@query}" unless type
77
- if type != String
78
- raise "find(#{@query}).between(#{lower}, #{upper}) to allowed since #{lower} is not a Float or Fixnum" if lower === Float or lower === Fixnum
79
- raise "find(#{@query}).between(#{lower}, #{upper}) to allowed since #{upper} is not a Float or Fixnum" if upper === Float or upper === Fixnum
80
- @query = org.apache.lucene.search.NumericRangeQuery.new_double_range(@query.to_s, lower, upper, false, false)
81
- else
82
- raise "find(#{@query}).between(#{lower}, #{upper}) to allowed since #{lower} is not a String" if lower === String
83
- raise "find(#{@query}).between(#{lower}, #{upper}) to allowed since #{upper} is not a String" if upper === String
84
- @query = org.apache.lucene.search.TermRangeQuery.new(@query.to_s, lower, upper, false, false)
85
- end
92
+ # check that we perform a range query on the same values as we have declared with the property :key, :type => ...
93
+ type = @decl_props[@query] && @decl_props[@query][:type]
94
+ raise "find(#{@query}).between(#{lower}, #{upper}): #{lower} not a #{type}" if type && !type === lower.class
95
+ raise "find(#{@query}).between(#{lower}, #{upper}): #{upper} not a #{type}" if type && !type === upper.class
96
+
97
+ # Make it possible to convert those values
98
+ lower = TypeConverters.convert(lower)
99
+ upper = TypeConverters.convert(upper)
100
+
101
+ @query = case lower
102
+ when Fixnum
103
+ org.apache.lucene.search.NumericRangeQuery.new_long_range(@query.to_s, lower, upper, lower_incusive, upper_inclusive)
104
+ when Float
105
+ org.apache.lucene.search.NumericRangeQuery.new_double_range(@query.to_s, lower, upper, lower_incusive, upper_inclusive)
106
+ else
107
+ org.apache.lucene.search.TermRangeQuery.new(@query.to_s, lower, upper, lower_incusive, upper_inclusive)
108
+ end
86
109
  self
87
110
  end
88
111
 
112
+ # Create a compound lucene query.
113
+ #
114
+ # ==== Parameters
115
+ # query2 :: the query that should be AND together
116
+ #
117
+ # ==== Example
118
+ #
119
+ # Person.find(:name=>'kalle').and(:age => 3)
120
+ #
89
121
  def and(query2)
90
122
  new_query = LuceneQuery.new(@index, @decl_props, query2)
91
123
  new_query.left_and_query = self
92
124
  new_query
93
125
  end
94
126
 
127
+
128
+ # Sort descending the given fields.
95
129
  def desc(*fields)
96
130
  @order = fields.inject(@order || {}) { |memo, field| memo[field] = true; memo }
97
131
  self
98
132
  end
99
133
 
134
+ # Sort ascending the given fields.
100
135
  def asc(*fields)
101
136
  @order = fields.inject(@order || {}) { |memo, field| memo[field] = false; memo }
102
137
  self
103
138
  end
104
139
 
105
- def build_and_query(query)
140
+ def build_and_query(query) #:nodoc:
106
141
  left_query = @left_and_query.build_query
107
142
  and_query = org.apache.lucene.search.BooleanQuery.new
108
143
  and_query.add(left_query, org.apache.lucene.search.BooleanClause::Occur::MUST)
@@ -110,7 +145,7 @@ module Neo4j
110
145
  and_query
111
146
  end
112
147
 
113
- def build_sort_query(query)
148
+ def build_sort_query(query) #:nodoc:
114
149
  java_sort_fields = @order.keys.inject([]) do |memo, field|
115
150
  decl_type = @decl_props && @decl_props[field] && @decl_props[field][:type]
116
151
  type = case
@@ -127,7 +162,7 @@ module Neo4j
127
162
  org.neo4j.index.impl.lucene.QueryContext.new(query).sort(sort)
128
163
  end
129
164
 
130
- def build_hash_query(query)
165
+ def build_hash_query(query) #:nodoc:
131
166
  and_query = org.apache.lucene.search.BooleanQuery.new
132
167
 
133
168
  query.each_pair do |key, value|
@@ -139,7 +174,7 @@ module Neo4j
139
174
  and_query
140
175
  end
141
176
 
142
- def build_query
177
+ def build_query #:nodoc:
143
178
  query = @query
144
179
  query = build_hash_query(query) if Hash === query
145
180
  query = build_and_query(query) if @left_and_query
@@ -147,7 +182,7 @@ module Neo4j
147
182
  query
148
183
  end
149
184
 
150
- def perform_query
185
+ def perform_query #:nodoc:
151
186
  @index.query(build_query)
152
187
  end
153
188
  end
@@ -49,15 +49,14 @@ module Neo4j::Mapping
49
49
  props.each do |prop|
50
50
  pname = prop.to_sym
51
51
  _decl_props[pname] ||= {}
52
- _decl_props[pname][:defined] = true
53
52
 
54
53
  define_method(pname) do
55
- self[pname]
54
+ Neo4j::TypeConverters.to_ruby(self.class, pname, self[pname])
56
55
  end
57
56
 
58
57
  name = (pname.to_s() +"=").to_sym
59
58
  define_method(name) do |value|
60
- self[pname] = value
59
+ self[pname] = Neo4j::TypeConverters.to_java(self.class, pname, value)
61
60
  end
62
61
  end
63
62
  end
@@ -46,7 +46,7 @@ module Neo4j::Mapping
46
46
  def init_on_create(*args) # :nodoc:
47
47
  self[:_classname] = self.class.to_s
48
48
  if args[0].respond_to?(:each_pair)
49
- args[0].each_pair { |k, v| @_java_node.set_property(k.to_s, v) }
49
+ args[0].each_pair { |k, v| respond_to?("#{k}=")? self.send("#{k}=", v) : @_java_node[k] = v }
50
50
  end
51
51
  end
52
52
 
data/lib/neo4j/node.rb CHANGED
@@ -96,7 +96,7 @@ module Neo4j
96
96
  db = (!props && args[0]) || args[1] || Neo4j.started_db
97
97
 
98
98
  node = db.graph.create_node
99
- props.each_pair { |k, v| node.set_property(k.to_s, v) } if props
99
+ props.each_pair { |k, v| node[k]= v } if props
100
100
  node
101
101
  end
102
102
 
@@ -69,20 +69,42 @@ module Neo4j
69
69
  # Returns the value of the given key or nil if the property does not exist.
70
70
  def [](key)
71
71
  return unless property?(key)
72
- get_property(key.to_s)
72
+ val = get_property(key.to_s)
73
+ val.class.superclass == ArrayJavaProxy ? val.to_a : val
73
74
  end
74
75
 
75
76
  # Sets the property of this node.
76
- # Property keys are always strings. Valid property value types are the primitives(<tt>String</tt>, <tt>Fixnum</tt>, <tt>Float</tt>, <tt>Boolean</tt>).
77
+ # Property keys are always strings. Valid property value types are the primitives(<tt>String</tt>, <tt>Fixnum</tt>, <tt>Float</tt>, <tt>FalseClass</tt>, <tt>TrueClass</tt>) or array of those primitives.
78
+ #
79
+ # ==== Gotchas
80
+ # * Values in the array must be of the same type.
81
+ # * You can *not* delete or add one item in the array (e.g. person.phones.delete('123')) but instead you must create a new array instead.
77
82
  #
78
83
  def []=(key, value)
79
84
  k = key.to_s
80
85
  if value.nil?
81
86
  remove_property(k)
87
+ elsif (Array === value)
88
+ case value[0]
89
+ when NilClass
90
+ set_property(k, [].to_java(:string))
91
+ when String
92
+ set_property(k, value.to_java(:string))
93
+ when Float
94
+ set_property(k, value.to_java(:double))
95
+ when FalseClass, TrueClass
96
+ set_property(k, value.to_java(:boolean))
97
+ when Fixnum
98
+ set_property(k, value.to_java(:long))
99
+ when Boolean
100
+ set_property(k, value.to_java(:boolean))
101
+ else
102
+ raise "Not allowed to store array with value #{value[0]} type #{value[0].class}"
103
+ end
82
104
  else
83
105
  set_property(k, value)
84
106
  end
85
107
  end
86
- end
87
108
 
109
+ end
88
110
  end
@@ -181,6 +181,7 @@ module Neo4j
181
181
  return false unless _java_node.save_nested(node)
182
182
  init_on_load(node)
183
183
  init_on_create
184
+ self.created_at = DateTime.now if Neo4j::Config[:timestamps] && respond_to?(:created_at)
184
185
  clear_changes
185
186
  true
186
187
  end
@@ -189,6 +190,7 @@ module Neo4j
189
190
  _run_update_callbacks do
190
191
  if valid?(:update)
191
192
  clear_changes
193
+ self.updated_at = DateTime.now if Neo4j::Config[:timestamps] && respond_to?(:updated_at)
192
194
  true
193
195
  end
194
196
  end
@@ -0,0 +1,84 @@
1
+ module Neo4j
2
+
3
+ # Responsible for converting values from and to Java Neo4j and Lucene.
4
+ # You can implement your own converter by implementing the method <tt>to_java</tt> and <tt>to_ruby</tt>
5
+ # and add it to the Neo4j::Config with the key <tt>:converters</tt>
6
+ #
7
+ # There are currently two default converters that are triggered when a Date or a DateTime is read or written.
8
+ #
9
+ module TypeConverters
10
+
11
+ # Converts Date objects to Java long types. Must be timezone UTC.
12
+ class DateConverter
13
+ class << self
14
+ def to_java(value)
15
+ return nil if value.nil?
16
+ Time.utc(value.year, value.month, value.day).to_i
17
+ end
18
+
19
+ def to_ruby(value)
20
+ return nil if value.nil?
21
+ Time.at(value).utc
22
+ end
23
+ end
24
+ end
25
+
26
+ # Converts DateTime objects to and from Java long types. Must be timezone UTC.
27
+ class DateTimeConverter
28
+ class << self
29
+ # Converts the given DateTime (UTC) value to an Fixnum.
30
+ # Only utc times are supported !
31
+ def to_java(value)
32
+ return nil if value.nil?
33
+ Time.utc(value.year, value.month, value.day, value.hour, value.min, value.sec).to_i
34
+ end
35
+
36
+ def to_ruby(value)
37
+ return nil if value.nil?
38
+ t = Time.at(value).utc
39
+ DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec)
40
+ end
41
+ end
42
+ end
43
+
44
+ # Converts the given value to a Java type by using the registered converters.
45
+ # It just looks at the class of the given value and will convert it if there is a converter
46
+ # registered (in Neo4j::Config) for this value.
47
+ def self.convert(value)
48
+ type = value.class
49
+ converter = Neo4j::Config[:converters][type]
50
+ return value unless converter
51
+ converter.to_java(value)
52
+ end
53
+
54
+ # Converts the given property (key, value) to Java by using configuration from the given class.
55
+ # If no Converter is defined for this value then it simply returns the given value.
56
+ def self.to_java(clazz, key, value)
57
+ type = clazz._decl_props[key] && clazz._decl_props[key][:type]
58
+ if type
59
+ converter = Neo4j::Config[:converters][type]
60
+ converter ? converter.to_java(value) : value
61
+ elsif clazz.superclass != Object
62
+ to_java(clazz.superclass, key, value)
63
+ else
64
+ value
65
+ end
66
+ end
67
+
68
+ # Converts the given property (key, value) to Ruby by using configuration from the given class.
69
+ # If no Converter is defined for this value then it simply returns the given value.
70
+ def self.to_ruby(clazz, key, value)
71
+ type = clazz._decl_props[key] && clazz._decl_props[key][:type]
72
+ if type
73
+ converter = Neo4j::Config[:converters][type]
74
+ converter ? converter.to_ruby(value) : value
75
+ elsif clazz.superclass != Object
76
+ to_ruby(clazz.superclass, key, value)
77
+ else
78
+ value
79
+ end
80
+ end
81
+
82
+ Neo4j::Config[:converters] = {Date => DateConverter, DateTime => DateTimeConverter}
83
+ end
84
+ end
data/lib/neo4j/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Neo4j
2
- VERSION = "1.0.0.beta.18"
2
+ VERSION = "1.0.0.beta.19"
3
3
  end
metadata CHANGED
@@ -7,8 +7,8 @@ version: !ruby/object:Gem::Version
7
7
  - 0
8
8
  - 0
9
9
  - beta
10
- - 18
11
- version: 1.0.0.beta.18
10
+ - 19
11
+ version: 1.0.0.beta.19
12
12
  platform: ruby
13
13
  authors:
14
14
  - Andreas Ronge
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-11-04 00:00:00 +01:00
19
+ date: 2010-11-05 00:00:00 +01:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -64,6 +64,7 @@ files:
64
64
  - lib/generators/neo4j/model/templates/model.rb
65
65
  - lib/neo4j/event_handler.rb
66
66
  - lib/neo4j/model.rb
67
+ - lib/neo4j/type_converters.rb
67
68
  - lib/neo4j/node_traverser.rb
68
69
  - lib/neo4j/relationship_traverser.rb
69
70
  - lib/neo4j/config.rb
@@ -88,11 +89,11 @@ files:
88
89
  - lib/neo4j/rails/properties.rb
89
90
  - lib/neo4j/rails/value.rb
90
91
  - lib/neo4j/rails/validations/uniqueness.rb
91
- - lib/neo4j/jars/lucene-core-3.0.1.jar
92
92
  - lib/neo4j/jars/geronimo-jta_1.1_spec-1.1.1.jar
93
- - lib/neo4j/jars/neo4j-lucene-index-0.2-1.2.M02.jar
94
- - lib/neo4j/jars/neo4j-kernel-1.2-1.2.M02.jar
95
- - lib/neo4j/jars/neo4j-index-1.2-1.2.M02.jar
93
+ - lib/neo4j/jars/lucene-core-3.0.2.jar
94
+ - lib/neo4j/jars/neo4j-index-1.2-1.2.M03.jar
95
+ - lib/neo4j/jars/neo4j-lucene-index-0.2-1.2.M03.jar
96
+ - lib/neo4j/jars/neo4j-kernel-1.2-1.2.M03.jar
96
97
  - lib/neo4j/mapping/decl_relationship_dsl.rb
97
98
  - lib/neo4j/mapping/node_mixin.rb
98
99
  - lib/neo4j/mapping/has_n.rb