rroonga 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/ext/groonga/rb-grn.h CHANGED
@@ -76,7 +76,7 @@ RB_GRN_BEGIN_DECLS
76
76
 
77
77
  #define RB_GRN_MAJOR_VERSION 3
78
78
  #define RB_GRN_MINOR_VERSION 0
79
- #define RB_GRN_MICRO_VERSION 1
79
+ #define RB_GRN_MICRO_VERSION 2
80
80
 
81
81
  #define RB_GRN_QUERY_DEFAULT_MAX_EXPRESSIONS 32
82
82
 
@@ -616,8 +616,8 @@ VALUE rb_grn_column_expression_builder_build
616
616
 
617
617
  #define RVAL2GRNUVECTOR(object, context, uvector, related_object) \
618
618
  (rb_grn_uvector_from_ruby_object(object, context, uvector, related_object))
619
- #define GRNUVECTOR2RVAL(context, uvector) \
620
- (rb_grn_uvector_to_ruby_object(context, uvector))
619
+ #define GRNUVECTOR2RVAL(context, uvector, range, related_object) \
620
+ (rb_grn_uvector_to_ruby_object(context, uvector, range, related_object))
621
621
 
622
622
  #define GRNVALUE2RVAL(context, value, range, related_object) \
623
623
  (rb_grn_value_to_ruby_object(context, value, range, related_object))
@@ -735,7 +735,9 @@ grn_obj *rb_grn_uvector_from_ruby_object (VALUE object,
735
735
  grn_obj *uvector,
736
736
  VALUE related_object);
737
737
  VALUE rb_grn_uvector_to_ruby_object (grn_ctx *context,
738
- grn_obj *uvector);
738
+ grn_obj *uvector,
739
+ grn_obj *range,
740
+ VALUE related_object);
739
741
 
740
742
  VALUE rb_grn_value_to_ruby_object (grn_ctx *context,
741
743
  grn_obj *value,
@@ -54,15 +54,12 @@ module Groonga
54
54
  options[:context] ||= Groonga::Context.default
55
55
  options[:database] = options[:context].database
56
56
  end
57
- options[:dump_plugins] = true if options[:dump_plugins].nil?
58
57
  options[:dump_schema] = true if options[:dump_schema].nil?
59
58
  options[:dump_tables] = true if options[:dump_tables].nil?
60
59
 
61
60
  if options[:dump_schema]
61
+ dump_plugins(options)
62
62
  schema_dumper = SchemaDumper.new(options.merge(:syntax => :command))
63
- end
64
- dump_plugins(options) if options[:dump_plugins]
65
- if options[:dump_schema]
66
63
  schema_dumper.dump_tables
67
64
  if schema_dumper.have_reference_columns?
68
65
  options[:output].write("\n")
@@ -102,6 +99,7 @@ module Groonga
102
99
  options[:database].each(each_options(:order_by => :key)) do |object|
103
100
  next unless object.is_a?(Groonga::Table)
104
101
  next if object.size.zero?
102
+ next if index_only_table?(object)
105
103
  next if target_table?(options[:exclude_tables], object, false)
106
104
  next unless target_table?(options[:tables], object, true)
107
105
  options[:output].write("\n") if !first_table or options[:dump_schema]
@@ -124,6 +122,12 @@ module Groonga
124
122
  output.write("register #{plugin_name}\n")
125
123
  end
126
124
 
125
+ def index_only_table?(table)
126
+ table.columns.all? do |column|
127
+ column.index?
128
+ end
129
+ end
130
+
127
131
  def target_table?(target_tables, table, default_value)
128
132
  return default_value if target_tables.nil? or target_tables.empty?
129
133
  target_tables.any? do |name|
@@ -277,8 +281,17 @@ module Groonga
277
281
 
278
282
  def each_table
279
283
  each_options = {:order_by => :key, :ignore_missing_object => true}
284
+ reference_tables = []
280
285
  @database.each(each_options) do |object|
281
- yield(object) if object.is_a?(Groonga::Table)
286
+ next unless object.is_a?(Groonga::Table)
287
+ if reference_table?(object)
288
+ reference_tables << object
289
+ else
290
+ yield(object)
291
+ end
292
+ end
293
+ reference_tables.each do |table|
294
+ yield(table)
282
295
  end
283
296
  end
284
297
 
@@ -287,7 +300,7 @@ module Groonga
287
300
  sorted_columns.each(&block)
288
301
  end
289
302
 
290
- def collect_columns
303
+ def find_all_columns
291
304
  columns = []
292
305
  each_table do |table|
293
306
  each_column(table) do |column|
@@ -298,13 +311,13 @@ module Groonga
298
311
  end
299
312
 
300
313
  def reference_columns
301
- @reference_columns ||= collect_columns do |column|
314
+ @reference_columns ||= find_all_columns do |column|
302
315
  reference_column?(column)
303
316
  end
304
317
  end
305
318
 
306
319
  def index_columns
307
- @index_columns ||= collect_columns do |column|
320
+ @index_columns ||= find_all_columns do |column|
308
321
  index_column?(column)
309
322
  end
310
323
  end
@@ -333,6 +346,10 @@ module Groonga
333
346
  write("\n")
334
347
  end
335
348
 
349
+ def reference_table?(table)
350
+ table.support_key? and table.domain.is_a?(Groonga::Table)
351
+ end
352
+
336
353
  def column_type(column)
337
354
  if column.is_a?(Groonga::IndexColumn)
338
355
  :index
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2009-2011 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2009-2013 Kouhei Sutou <kou@clear-code.com>
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -16,6 +16,7 @@
16
16
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
 
18
18
  require 'English'
19
+ require "time"
19
20
 
20
21
  module Groonga
21
22
  class Record
@@ -253,6 +254,22 @@ module Groonga
253
254
  accessor.build
254
255
  end
255
256
 
257
+ def as_json
258
+ accessor = AttributeHashBuilder.new(self) do |value|
259
+ if value.is_a?(Time)
260
+ value.iso8601
261
+ else
262
+ value
263
+ end
264
+ end
265
+ accessor.build
266
+ end
267
+
268
+ # @return [String] the record formatted as JSON.
269
+ def to_json(*args)
270
+ as_json.to_json(*args)
271
+ end
272
+
256
273
  # レコードを削除する。
257
274
  def delete
258
275
  @table.delete(@id)
@@ -384,9 +401,10 @@ module Groonga
384
401
  class AttributeHashBuilder
385
402
  attr_reader :attributes
386
403
 
387
- def initialize(root_record)
404
+ def initialize(root_record, &value_translator)
388
405
  @root_record = root_record
389
406
  @all_built_attributes = {}
407
+ @value_translator = value_translator
390
408
  end
391
409
 
392
410
  def build
@@ -415,6 +433,7 @@ module Groonga
415
433
  if value.is_a?(Record)
416
434
  build_attributes(value)
417
435
  else
436
+ value = @value_translator.call(value) if @value_translator
418
437
  value
419
438
  end
420
439
  end
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2009-2011 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2009-2013 Kouhei Sutou <kou@clear-code.com>
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -1463,7 +1463,7 @@ module Groonga
1463
1463
  return false unless table.range == resolve_name(options[:value_type])
1464
1464
  sub_records = options[:sub_records]
1465
1465
  sub_records = false if sub_records.nil?
1466
- return false unless table.support_sub_records? == sub_records
1466
+ return false unless table.have_n_sub_records_space? == sub_records
1467
1467
 
1468
1468
  case table
1469
1469
  when Groonga::Array
data/rroonga-build.rb CHANGED
@@ -19,7 +19,7 @@ module RroongaBuild
19
19
  module RequiredGroongaVersion
20
20
  MAJOR = 3
21
21
  MINOR = 0
22
- MICRO = 3
22
+ MICRO = 4
23
23
  VERSION = [MAJOR, MINOR, MICRO]
24
24
  end
25
25
 
data/rroonga.gemspec CHANGED
@@ -79,6 +79,8 @@ Gem::Specification.new do |s|
79
79
  s.require_paths = ["lib"]
80
80
  s.rubyforge_project = "groonga"
81
81
 
82
+ s.required_ruby_version = ">= 1.9.3"
83
+
82
84
  s.add_runtime_dependency("pkg-config")
83
85
  s.add_runtime_dependency("json")
84
86
  s.add_runtime_dependency("archive-zip")
@@ -107,13 +107,13 @@ column_create Users Posts_author COLUMN_INDEX Posts author
107
107
  EOS
108
108
  end
109
109
 
110
- class EmptyTest < DatabaseDumperTest
110
+ class EmptyTest < self
111
111
  def test_default
112
112
  assert_equal(dumped_schema, dump)
113
113
  end
114
114
  end
115
115
 
116
- class HaveDataTest < DatabaseDumperTest
116
+ class HaveDataTest < self
117
117
  setup
118
118
  def setup_data
119
119
  posts.add(:author => "mori",
@@ -287,7 +287,7 @@ EOS
287
287
  end
288
288
  end
289
289
 
290
- class PluginTest < DatabaseDumperTest
290
+ class PluginTest < self
291
291
  def test_standard_plugin
292
292
  Groonga::Plugin.register("suggest/suggest")
293
293
  assert_equal("register suggest/suggest\n" +
@@ -296,4 +296,46 @@ EOS
296
296
  dump)
297
297
  end
298
298
  end
299
+
300
+ class IndexTest < self
301
+ def setup_tables
302
+ Groonga::Schema.define do |schema|
303
+ schema.create_table("Posts") do |table|
304
+ table.text("title")
305
+ table.short_text("tag_text")
306
+ end
307
+
308
+ schema.create_table("Tags",
309
+ :type => :hash,
310
+ :key_type => :short_text,
311
+ :default_tokenizer => :delimit) do |table|
312
+ table.index("Posts.tag_text")
313
+ end
314
+ end
315
+ end
316
+
317
+ setup
318
+ def setup_data
319
+ posts.add(:title => "Why search engine find?",
320
+ :tag_text => "search mori")
321
+ end
322
+
323
+ def test_index_column_only
324
+ assert_equal(<<-COMMAND, dump)
325
+ table_create Posts TABLE_NO_KEY
326
+ column_create Posts tag_text COLUMN_SCALAR ShortText
327
+ column_create Posts title COLUMN_SCALAR Text
328
+
329
+ table_create Tags TABLE_HASH_KEY --key_type ShortText --default_tokenizer TokenDelimit
330
+
331
+ load --table Posts
332
+ [
333
+ ["_id","tag_text","title"],
334
+ [1,"search mori","Why search engine find?"]
335
+ ]
336
+
337
+ column_create Tags Posts_tag_text COLUMN_INDEX Posts tag_text
338
+ COMMAND
339
+ end
340
+ end
299
341
  end
@@ -626,18 +626,5 @@ EOC
626
626
  assert_equal([["morita", 2]],
627
627
  result.collect {|record| [record["_key"], record.key.score]})
628
628
  end
629
-
630
- def test_n_sub_records
631
- result = @users.select do |record|
632
- (record.name =~ "o") | (record.key == "yu")
633
- end
634
- result = result.select do |record|
635
- record.n_sub_records > 1
636
- end
637
- matched_records = result.collect do |record|
638
- [record["_key"], record.key.n_sub_records]
639
- end
640
- assert_equal([["yu", 2]], matched_records)
641
- end
642
629
  end
643
630
  end
@@ -64,14 +64,45 @@ class FixSizeColumnTest < Test::Unit::TestCase
64
64
  assert_equal(@bookmarks, @viewed.table)
65
65
  end
66
66
 
67
- def test_assign_time
68
- comments = Groonga::Array.create(:name => "Comments")
69
- comments.define_column("title", "ShortText")
70
- comments.define_column("issued", "Time")
71
- title = "Good"
72
- issued = 1187430026
73
- record = comments.add(:title => title, :issued => issued)
74
- assert_equal([title, Time.at(issued)],
75
- [record["title"], record["issued"]])
67
+ class TimeTest < self
68
+ class IntegerTest < self
69
+ def test_assign
70
+ comments = Groonga::Array.create(:name => "Comments")
71
+ comments.define_column("issued", "Time")
72
+ issued = 1187430026
73
+ record = comments.add(:issued => issued)
74
+ assert_equal(Time.at(issued), record["issued"])
75
+ end
76
+ end
77
+
78
+ class FloatTest < self
79
+ def test_assign
80
+ comments = Groonga::Array.create(:name => "Comments")
81
+ comments.define_column("issued", "Time")
82
+ issued = 1187430026.29
83
+ record = comments.add(:issued => issued)
84
+ assert_in_delta(issued, record["issued"].to_f, 0.001)
85
+ end
86
+ end
87
+
88
+ class TimeTest < self
89
+ def test_assign
90
+ comments = Groonga::Array.create(:name => "Comments")
91
+ comments.define_column("issued", "Time")
92
+ issued_in_float = 1187430026.29
93
+ issued = Time.at(issued_in_float)
94
+ record = comments.add(:issued => issued)
95
+ assert_in_delta(issued_in_float, record["issued"].to_f, 0.001)
96
+ end
97
+ end
98
+
99
+ class StringTest < self
100
+ def test_assign
101
+ comments = Groonga::Array.create(:name => "Comments")
102
+ comments.define_column("issued", "Time")
103
+ record = comments.add(:issued => "2010/06/01 00:00:00")
104
+ assert_equal(Time.new(2010, 6, 1, 0, 0, 0), record["issued"])
105
+ end
106
+ end
76
107
  end
77
108
  end
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2009-2011 Kouhei Sutou <kou@clear-code.com>
3
+ # Copyright (C) 2009-2013 Kouhei Sutou <kou@clear-code.com>
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -88,6 +88,135 @@ class IndexColumnTest < Test::Unit::TestCase
88
88
  content_index.search("エンジン").collect {|record| record.key})
89
89
  end
90
90
 
91
+ def test_add
92
+ articles = Groonga::Array.create(:name => "Articles")
93
+ articles.define_column("content", "Text")
94
+
95
+ terms = Groonga::Hash.create(:name => "Terms",
96
+ :key_type => "ShortText",
97
+ :default_tokenizer => "TokenBigram")
98
+ content_index = terms.define_index_column("content", articles,
99
+ :with_position => true,
100
+ :with_section => true)
101
+
102
+ content = <<-CONTENT
103
+ Groonga is a fast and accurate full text search engine based on
104
+ inverted index. One of the characteristics of groonga is that a
105
+ newly registered document instantly appears in search
106
+ results. Also, groonga allows updates without read locks. These
107
+ characteristics result in superior performance on real-time
108
+ applications.
109
+
110
+ Groonga is also a column-oriented database management system
111
+ (DBMS). Compared with well-known row-oriented systems, such as
112
+ MySQL and PostgreSQL, column-oriented systems are more suited for
113
+ aggregate queries. Due to this advantage, groonga can cover
114
+ weakness of row-oriented systems.
115
+
116
+ The basic functions of groonga are provided in a C library. Also,
117
+ libraries for using groonga in other languages, such as Ruby, are
118
+ provided by related projects. In addition, groonga-based storage
119
+ engines are provided for MySQL and PostgreSQL. These libraries
120
+ and storage engines allow any application to use groonga. See
121
+ usage examples.
122
+ CONTENT
123
+
124
+ groonga = articles.add(:content => content)
125
+
126
+ content.split(/\n{2,}/).each_with_index do |sentence, i|
127
+ content_index.add(groonga, sentence, :section => i + 1)
128
+ end
129
+ assert_equal([groonga], content_index.search("engine").collect(&:key))
130
+ end
131
+
132
+ def test_delete
133
+ articles = Groonga::Array.create(:name => "Articles")
134
+ articles.define_column("content", "Text")
135
+
136
+ terms = Groonga::Hash.create(:name => "Terms",
137
+ :key_type => "ShortText",
138
+ :default_tokenizer => "TokenBigram")
139
+ content_index = terms.define_index_column("content", articles,
140
+ :with_position => true,
141
+ :with_section => true)
142
+
143
+ content = <<-CONTENT
144
+ Groonga is a fast and accurate full text search engine based on
145
+ inverted index. One of the characteristics of groonga is that a
146
+ newly registered document instantly appears in search
147
+ results. Also, groonga allows updates without read locks. These
148
+ characteristics result in superior performance on real-time
149
+ applications.
150
+
151
+ Groonga is also a column-oriented database management system
152
+ (DBMS). Compared with well-known row-oriented systems, such as
153
+ MySQL and PostgreSQL, column-oriented systems are more suited for
154
+ aggregate queries. Due to this advantage, groonga can cover
155
+ weakness of row-oriented systems.
156
+
157
+ The basic functions of groonga are provided in a C library. Also,
158
+ libraries for using groonga in other languages, such as Ruby, are
159
+ provided by related projects. In addition, groonga-based storage
160
+ engines are provided for MySQL and PostgreSQL. These libraries
161
+ and storage engines allow any application to use groonga. See
162
+ usage examples.
163
+ CONTENT
164
+
165
+ groonga = articles.add(:content => content)
166
+
167
+ content.split(/\n{2,}/).each_with_index do |sentence, i|
168
+ content_index.add(groonga, sentence, :section => i + 1)
169
+ end
170
+ content.split(/\n{2,}/).each_with_index do |sentence, i|
171
+ content_index.delete(groonga, sentence, :section => i + 1)
172
+ end
173
+ assert_equal([], content_index.search("engine").collect(&:key))
174
+ end
175
+
176
+ def test_update
177
+ articles = Groonga::Array.create(:name => "Articles")
178
+ articles.define_column("content", "Text")
179
+
180
+ terms = Groonga::Hash.create(:name => "Terms",
181
+ :key_type => "ShortText",
182
+ :default_tokenizer => "TokenBigram")
183
+ content_index = terms.define_index_column("content", articles,
184
+ :with_position => true,
185
+ :with_section => true)
186
+
187
+ old_sentence = <<-SENTENCE
188
+ Groonga is a fast and accurate full text search engine based on
189
+ inverted index. One of the characteristics of groonga is that a
190
+ newly registered document instantly appears in search
191
+ results. Also, groonga allows updates without read locks. These
192
+ characteristics result in superior performance on real-time
193
+ applications.
194
+ SENTENCE
195
+
196
+ new_sentence = <<-SENTENCE
197
+ Groonga is also a column-oriented database management system
198
+ (DBMS). Compared with well-known row-oriented systems, such as
199
+ MySQL and PostgreSQL, column-oriented systems are more suited for
200
+ aggregate queries. Due to this advantage, groonga can cover
201
+ weakness of row-oriented systems.
202
+ SENTENCE
203
+
204
+ groonga = articles.add(:content => old_sentence)
205
+
206
+ content_index.add(groonga, old_sentence, :section => 1)
207
+ assert_equal([groonga],
208
+ content_index.search("engine").collect(&:key))
209
+ assert_equal([],
210
+ content_index.search("MySQL").collect(&:key))
211
+
212
+ groonga[:content] = new_sentence
213
+ content_index.update(groonga, old_sentence, new_sentence, :section => 1)
214
+ assert_equal([],
215
+ content_index.search("engine").collect(&:key))
216
+ assert_equal([groonga],
217
+ content_index.search("MySQL").collect(&:key))
218
+ end
219
+
91
220
  def test_shorter_query_than_ngram
92
221
  articles = Groonga::Array.create(:name => "Articles")
93
222
  articles.define_column("content", "Text")