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

Sign up to get free protection for your applications and to get access to all the features.
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