dm-groonga-adapter 0.1.0.pre → 0.1.0.pre2

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/Rakefile CHANGED
@@ -8,7 +8,7 @@ begin
8
8
  gem.summary = %Q{datamapper adapter for groonga search engine}
9
9
  gem.description = gem.summary
10
10
  gem.email = "hello@hryk.info"
11
- gem.homepage = "http://github.com/hryk/dm-groonga-adapter"
11
+ gem.homepage = "http://hryk.github.com/dm-groonga-adapter"
12
12
  gem.authors = ["hiroyuki"]
13
13
 
14
14
  gem.add_dependency "groonga", ">= 0.9"
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- :minor: 1
3
2
  :patch: 0
4
- :build: pre
5
3
  :major: 0
4
+ :build: pre2
5
+ :minor: 1
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{dm-groonga-adapter}
8
- s.version = "0.1.0.pre"
8
+ s.version = "0.1.0.pre2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["hiroyuki"]
12
- s.date = %q{2010-04-08}
12
+ s.date = %q{2010-04-15}
13
13
  s.description = %q{datamapper adapter for groonga search engine}
14
14
  s.email = %q{hello@hryk.info}
15
15
  s.extra_rdoc_files = [
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
27
27
  "examples/basic.rb",
28
28
  "lib/groonga_adapter.rb",
29
29
  "lib/groonga_adapter/adapter.rb",
30
+ "lib/groonga_adapter/jsonparser.rb",
30
31
  "lib/groonga_adapter/local_index.rb",
31
32
  "lib/groonga_adapter/model_ext.rb",
32
33
  "lib/groonga_adapter/remote_index.rb",
@@ -42,7 +43,7 @@ Gem::Specification.new do |s|
42
43
  "spec/specs/remote_result_spec.rb",
43
44
  "spec/specs/search_spec.rb"
44
45
  ]
45
- s.homepage = %q{http://github.com/hryk/dm-groonga-adapter}
46
+ s.homepage = %q{http://hryk.github.com/dm-groonga-adapter}
46
47
  s.rdoc_options = ["--charset=UTF-8"]
47
48
  s.require_paths = ["lib"]
48
49
  s.rubygems_version = %q{1.3.6}
@@ -3,6 +3,10 @@ module DataMapper
3
3
  module Adapters
4
4
  class GroongaAdapter < AbstractAdapter
5
5
 
6
+ # Initialize adapter
7
+ #
8
+ # @param [String] name
9
+ # @param [Hash] options the options passed to RemoteIndex or LocalIndex.
6
10
  def initialize(name, options)
7
11
  super
8
12
  Groonga::Context.default = nil # Reset Groonga::Context
@@ -0,0 +1,336 @@
1
+ # = Simple JSON parser & builder
2
+ #
3
+ # Author:: Chihiro Ito
4
+ # License:: Public domain (unlike other files)
5
+ # Support:: http://groups.google.com/group/webos-goodies/
6
+ #
7
+ # This file contains two simple JSON processing classes. JsonParser
8
+ # converts a JSON string to an array or a hash. JsonBuilder performs
9
+ # vice versa. These classes are standard compliant and are designed for
10
+ # stability and reliability. Especially JsonParser has UTF-8 validation
11
+ # functionality so you can avoid some kind of security attack.
12
+
13
+ require 'strscan'
14
+ require 'json' if RUBY_VERSION >= '1.9.0'
15
+
16
+
17
+ # = Simple JSON parser
18
+ #
19
+ # This class converts a JSON string to an array or a hash. If *json_str*
20
+ # contains a JSON form string, you can convert it like below.
21
+ #
22
+ # ruby_obj = JsonParser.new.parse(json_str)
23
+ #
24
+ # If *json_str* has one or more invalid UTF-8 sequence, JsonParser throws
25
+ # exception by default. You can change this behavior to replacing with an
26
+ # arbitrary unicode character. See below for details.
27
+ class JsonParser
28
+
29
+ #:stopdoc:
30
+ RUBY19 = RUBY_VERSION >= '1.9.0'
31
+ Debug = false
32
+ Name = 'JsonParser'
33
+ ERR_IllegalSyntax = "[#{Name}] Syntax error"
34
+ ERR_IllegalUnicode = "[#{Name}] Illegal unicode sequence"
35
+
36
+ StringRegex = /\s*"((?:\\.|[^"\\])*)"/n
37
+ ValueRegex = /\s*(?:
38
+ (true)|(false)|(null)| # 1:true, 2:false, 3:null
39
+ (?:\"((?:\\.|[^\"\\])*)\")| # 4:String
40
+ ([-+]?\d+\.\d+(?:[eE][-+]?\d+)?)| # 5:Float
41
+ ([-+]?\d+)| # 6:Integer
42
+ (\{)|(\[))/xn # 7:Hash, 8:Array
43
+ #:startdoc:
44
+
45
+ # Create a new instance of JsonParser. *options* can contain these values.
46
+ # [:validation]
47
+ # If set to false, UTF-8 validation is disabled. true by default.
48
+ # [:surrogate]
49
+ # If set to false, surrogate pair support is disabled. true by default.
50
+ # [:malformed_chr]
51
+ # An invalid sequence in JSON string will be replaced with this value.
52
+ # If set to nil, An exception will be thrown in this situation.
53
+ # nil by default.
54
+ # [:compatible]
55
+ # If set to true, Ruby1.9's JSON module is never used. false by default.
56
+ def initialize(options = {})
57
+ @default_validation = options.has_key?(:validation) ? options[:validation] : true
58
+ @default_surrogate = options.has_key?(:surrogate) ? options[:surrogate] : true
59
+ @default_malformed_chr = options.has_key?(:malformed_chr) ? options[:malformed_chr] : nil
60
+ @default_compatible = options.has_key?(:compatible) ? options[:compatible] : false
61
+ end
62
+
63
+ # Convert *str* to an array or hash.
64
+ # [str]
65
+ # A JSON form string. This must be encoded using UTF-8.
66
+ # [options]
67
+ # Same as new.
68
+ def parse(str, options = {})
69
+ @enable_validation = options.has_key?(:validation) ? options[:validation] : @default_validation
70
+ @enable_surrogate = options.has_key?(:surrogate) ? options[:surrogate] : @default_surrogate
71
+ @malformed_chr = options.has_key?(:malformed_chr) ? options[:malformed_chr] : @default_malformed_chr
72
+ @compatible = options.has_key?(:compatible) ? options[:compatible] : @default_compatible
73
+ @malformed_chr = @malformed_chr[0].ord if String === @malformed_chr
74
+ if RUBY19
75
+ str = (str.encode('UTF-8') rescue str.dup)
76
+ if @enable_validation && !@malformed_chr
77
+ raise err_msg(ERR_IllegalUnicode) unless str.valid_encoding?
78
+ @enable_validation = false
79
+ end
80
+ if !@enable_validation && @enable_surrogate && !@malformed_chr && !@compatible
81
+ begin
82
+ return JSON.parse(str, :max_nesting => false)
83
+ rescue JSON::JSONError => e
84
+ exception = RuntimeError.new(e.message)
85
+ exception.set_backtrace(e.backtrace)
86
+ raise exception
87
+ end
88
+ end
89
+ str.force_encoding('ASCII-8BIT')
90
+ end
91
+ @scanner = StringScanner.new(str)
92
+ obj = case get_symbol[0]
93
+ when ?{ then parse_hash
94
+ when ?[ then parse_array
95
+ else raise err_msg(ERR_IllegalSyntax)
96
+ end
97
+ @scanner = nil
98
+ obj
99
+ end
100
+
101
+ private #---------------------------------------------------------
102
+
103
+ def validate_string(str, malformed_chr = nil)
104
+ code = 0
105
+ rest = 0
106
+ range = nil
107
+ ucs = []
108
+ str.each_byte do |c|
109
+ if rest <= 0
110
+ case c
111
+ when 0x01..0x7f then rest = 0 ; ucs << c
112
+ when 0xc0..0xdf then rest = 1 ; code = c & 0x1f ; range = 0x00080..0x0007ff
113
+ when 0xe0..0xef then rest = 2 ; code = c & 0x0f ; range = 0x00800..0x00ffff
114
+ when 0xf0..0xf7 then rest = 3 ; code = c & 0x07 ; range = 0x10000..0x10ffff
115
+ else ucs << handle_malformed_chr(malformed_chr)
116
+ end
117
+ elsif (0x80..0xbf) === c
118
+ code = (code << 6) | (c & 0x3f)
119
+ if (rest -= 1) <= 0
120
+ if !(range === code) || (0xd800..0xdfff) === code
121
+ code = handle_malformed_chr(malformed_chr)
122
+ end
123
+ ucs << code
124
+ end
125
+ else
126
+ ucs << handle_malformed_chr(malformed_chr)
127
+ rest = 0
128
+ end
129
+ end
130
+ ucs << handle_malformed_chr(malformed_chr) if rest > 0
131
+ ucs.pack('U*')
132
+ end
133
+
134
+ def handle_malformed_chr(chr)
135
+ raise err_msg(ERR_IllegalUnicode) unless chr
136
+ chr
137
+ end
138
+
139
+ def err_msg(err)
140
+ err + (Debug ? " #{@scanner.string[[0, @scanner.pos - 8].max,16].inspect}" : "")
141
+ end
142
+
143
+ def unescape_string(str)
144
+ str = str.gsub(/\\(["\\\/bfnrt])/n) do
145
+ $1.tr('"\\/bfnrt', "\"\\/\b\f\n\r\t")
146
+ end.gsub(/(\\u[0-9a-fA-F]{4})+/n) do |matched|
147
+ seq = matched.scan(/\\u([0-9a-fA-F]{4})/n).flatten.map { |c| c.hex }
148
+ if @enable_surrogate
149
+ seq.each_index do |index|
150
+ if seq[index] && (0xd800..0xdbff) === seq[index]
151
+ n = index + 1
152
+ raise err_msg(ERR_IllegalUnicode) unless seq[n] && 0xdc00..0xdfff === seq[n]
153
+ seq[index] = 0x10000 + ((seq[index] & 0x03ff) << 10) + (seq[n] & 0x03ff)
154
+ seq[n] = nil
155
+ end
156
+ end.compact!
157
+ end
158
+ seq.pack('U*')
159
+ end
160
+ str = validate_string(str, @malformed_chr) if @enable_validation
161
+ RUBY19 ? str.force_encoding('UTF-8') : str
162
+ end
163
+
164
+ def get_symbol
165
+ raise err_msg(ERR_IllegalSyntax) unless @scanner.scan(/\s*(.)/n)
166
+ @scanner[1]
167
+ end
168
+
169
+ def peek_symbol
170
+ @scanner.match?(/\s*(.)/n) ? @scanner[1] : nil
171
+ end
172
+
173
+ def parse_string
174
+ raise err_msg(ERR_IllegalSyntax) unless @scanner.scan(StringRegex)
175
+ unescape_string(@scanner[1])
176
+ end
177
+
178
+ def parse_value
179
+ raise err_msg(ERR_IllegalSyntax) unless @scanner.scan(ValueRegex)
180
+ case
181
+ when @scanner[1] then true
182
+ when @scanner[2] then false
183
+ when @scanner[3] then nil
184
+ when @scanner[4] then unescape_string(@scanner[4])
185
+ when @scanner[5] then @scanner[5].to_f
186
+ when @scanner[6] then @scanner[6].to_i
187
+ when @scanner[7] then parse_hash
188
+ when @scanner[8] then parse_array
189
+ else raise err_msg(ERR_IllegalSyntax)
190
+ end
191
+ end
192
+
193
+ def parse_hash
194
+ obj = {}
195
+ if peek_symbol[0] == ?} then get_symbol ; return obj ; end
196
+ while true
197
+ index = parse_string
198
+ raise err_msg(ERR_IllegalSyntax) unless get_symbol[0] == ?:
199
+ value = parse_value
200
+ obj[index] = value
201
+ case get_symbol[0]
202
+ when ?} then return obj
203
+ when ?, then next
204
+ else raise err_msg(ERR_IllegalSyntax)
205
+ end
206
+ end
207
+ end
208
+
209
+ def parse_array
210
+ obj = []
211
+ if peek_symbol[0] == ?] then get_symbol ; return obj ; end
212
+ while true
213
+ obj << parse_value
214
+ case get_symbol[0]
215
+ when ?] then return obj
216
+ when ?, then next
217
+ else raise err_msg(ERR_IllegalSyntax)
218
+ end
219
+ end
220
+ end
221
+
222
+ end
223
+
224
+ # = Simple JSON builder
225
+ #
226
+ # This class converts an Ruby object to a JSON string. you can convert
227
+ # *ruby_obj* like below.
228
+ #
229
+ # json_str = JsonBuilder.new.build(ruby_obj)
230
+ #
231
+ # *ruby_obj* must satisfy these conditions.
232
+ # - It must support to_s method, otherwise must be an array, a hash or nil.
233
+ # - All keys of a hash must support to_s method.
234
+ # - All values of an array or a hash must satisfy all conditions mentioned above.
235
+ #
236
+ # If the *ruby_obj* is not an array or a hash, it will be converted to an array
237
+ # with a single element.
238
+ class JsonBuilder
239
+
240
+ #:stopdoc:
241
+ RUBY19 = RUBY_VERSION >= '1.9.0'
242
+ Name = 'JsonBuilder'
243
+ ERR_NestIsTooDeep = "[#{Name}] Array / Hash nested too deep."
244
+ ERR_NaN = "[#{Name}] NaN and Infinite are not permitted in JSON."
245
+ #:startdoc:
246
+
247
+ # Create a new instance of JsonBuilder. *options* can contain these values.
248
+ # [:max_nest]
249
+ # If Array / Hash is nested more than this value, an exception would be thrown.
250
+ # 19 by default.
251
+ # [:nan]
252
+ # NaN is replaced with this value. If nil or false, an exception will be thrown.
253
+ # nil by default.
254
+ def initialize(options = {})
255
+ @default_max_nest = options.has_key?(:max_nest) ? options[:max_nest] : 19
256
+ @default_nan = options.has_key?(:nan) ? options[:nan] : nil
257
+ end
258
+
259
+ # Convert *obj* to a JSON form string.
260
+ # [obj]
261
+ # A ruby object. this object must satisfy all conditions mentioned above.
262
+ # [options]
263
+ # Same as new.
264
+ def build(obj, options = {})
265
+ @max_nest = options.has_key?(:max_nest) ? options[:max_nest] : @default_max_nest
266
+ @nan = options.has_key?(:nan) ? options[:nan] : @default_nan
267
+ if RUBY19 && !@nan
268
+ begin
269
+ JSON.generate(obj, :max_nesting => @max_nest, :check_circular => false)
270
+ rescue JSON::JSONError => e
271
+ exception = RuntimeError.new(e.message)
272
+ exception.set_backtrace(e.backtrace)
273
+ raise exception
274
+ end
275
+ else
276
+ case obj
277
+ when Array then build_array(obj, 0)
278
+ when Hash then build_object(obj, 0)
279
+ else build_array([obj], 0)
280
+ end
281
+ end
282
+ end
283
+
284
+ private #---------------------------------------------------------
285
+
286
+ ESCAPE_CONVERSION = {
287
+ '"' => '\"', '\\' => '\\\\', '/' => '/', "\x08" => '\b',
288
+ "\x0c" => '\f', "\x0a" => '\n', "\x0d" => '\r', "\x09" => '\t'
289
+ }
290
+ if RUBY19
291
+ def escape(str)
292
+ str = str.to_s.encode('UTF-8')
293
+ str.force_encoding('ASCII-8BIT')
294
+ str = str.gsub(/[^\x20-\x21\x23-\x2e\x30-\x5b\x5d-\xff]/n) do |chr|
295
+ escaped = ESCAPE_CONVERSION[chr]
296
+ escaped = sprintf("\\u%04X", chr[0].ord) unless escaped
297
+ escaped
298
+ end
299
+ str.force_encoding('UTF-8')
300
+ "\"#{str}\""
301
+ end
302
+ else
303
+ def escape(str)
304
+ str = str.gsub(/[^\x20-\x21\x23-\x2e\x30-\x5b\x5d-\xff]/n) do |chr|
305
+ escaped = ESCAPE_CONVERSION[chr]
306
+ escaped = sprintf("\\u%04x", chr[0]) unless escaped
307
+ escaped
308
+ end
309
+ "\\\"#{str}\\\""
310
+ end
311
+ end
312
+
313
+ def build_value(obj, level)
314
+ case obj
315
+ when Integer, TrueClass, FalseClass then obj.to_s
316
+ when Float then raise ERR_NaN unless obj.finite? || (obj = @nan) ; obj.to_s
317
+ when NilClass then 'null'
318
+ when Array then build_array(obj, level + 1)
319
+ when Hash then build_object(obj, level + 1)
320
+ else escape(obj)
321
+ end
322
+ end
323
+
324
+ def build_array(obj, level)
325
+ raise ERR_NestIsTooDeep if level >= @max_nest
326
+ '[' + obj.map { |item| build_value(item, level) }.join(',') + ']'
327
+ end
328
+
329
+ def build_object(obj, level)
330
+ raise ERR_NestIsTooDeep if level >= @max_nest
331
+ '{' + obj.map do |item|
332
+ "#{build_value(item[0].to_s,level)}:#{build_value(item[1],level)}"
333
+ end.join(',') + '}'
334
+ end
335
+
336
+ end
@@ -141,6 +141,8 @@ module DataMapper
141
141
  return Groonga::Type::BOOL
142
142
  when "Serial"
143
143
  return Groonga::Type::UINT32
144
+ when "Text"
145
+ return Groonga::Type::TEXT
144
146
  end
145
147
  else
146
148
  return Groonga::Type::SHORT_TEXT
@@ -1,4 +1,5 @@
1
1
  require 'json'
2
+ require 'nkf'
2
3
 
3
4
  module DataMapper
4
5
  module Adapters
@@ -9,6 +10,7 @@ module DataMapper
9
10
  def initialize(options)
10
11
  @context = Groonga::Context.default
11
12
  @context.connect(:host => options[:host], :port => options[:port])
13
+ @jsonbuilder = JsonBuilder.new
12
14
  # request "status" # <- TODO check connection with status command
13
15
  end
14
16
 
@@ -17,8 +19,8 @@ module DataMapper
17
19
  doc_id = doc[:id] #doc.delete(:id)
18
20
  record = []
19
21
  record << doc.update("_key" => doc_id)
20
- json = JSON.generate record
21
- res = request "load --table #{table_name} --values #{Unicode.unescape(json.gsub(/"/, '\"').gsub(/\s/, '\ '))}"
22
+ values = escape_value record
23
+ res = request "load --table #{table_name} --values #{values}"
22
24
  result = GroongaResult::Count.new res
23
25
  if result.success? && result.count > 0
24
26
  return doc
@@ -37,9 +39,20 @@ module DataMapper
37
39
  # [offset [limit [drilldown [drilldown_sortby [drilldown_output_columns
38
40
  # [drilldown_offset [drilldown_limit [output_type]]]]]]]]]]]]]]
39
41
  def search(table_name, grn_query, grn_sort=[], options={})
42
+ # In case of columns contain long string, groonga return 10 results with no-limit..
43
+ # --limit #{num} option is needed to get all result.
44
+ # because of this, current remote_index request at twice.
40
45
  sort_by, offset, limit = parse_grn_sort grn_sort
41
- remote_query = (grn_query.empty?) ? "" : "--query #{grn_query}"
42
- remote_sort_by = (sort_by.empty?) ? "" : "--sort-by #{sort_by}"
46
+ remote_query = (grn_query.empty?) ? "" : "--query #{grn_query}"
47
+ remote_sort_by = (sort_by.empty?) ? "" : "--sortby #{sort_by}"
48
+ # 1st request for get count.
49
+
50
+ if limit.nil? or limit == -1
51
+ count = GroongaResult::List.new(request "select #{table_name} #{remote_query} #{remote_sort_by} --output_columns _id")
52
+ limit = count.size
53
+ end
54
+
55
+ # 2nd request for get ids.
43
56
  res = request "select #{table_name} #{remote_query} #{remote_sort_by} --offset #{offset} --limit #{limit}"
44
57
  list = GroongaResult::List.new res
45
58
  if list.success?
@@ -109,12 +122,66 @@ module DataMapper
109
122
 
110
123
  protected
111
124
 
125
+ def escape_value record
126
+ record.map! {|r|
127
+ tmp = {}
128
+ r.each {|k,v|
129
+ if !v.nil?
130
+ if v.is_a? String
131
+ tmp[k] = NKF.nkf('-wZ1',v)
132
+ tmp[k].gsub!(/\\/, '\\\\\\')
133
+ tmp[k].gsub!(/"/) { |c| "\\\\\\#{c}" }
134
+ else
135
+ tmp[k] = v.to_s
136
+ end
137
+ end
138
+ }
139
+ tmp
140
+ }
141
+ json = @jsonbuilder.build record
142
+ json.gsub!(/'|\s|\(|\)|\t/) { |c| "\\#{c}" }
143
+ json
144
+ end
145
+
112
146
  def err_code(res)
113
147
  return if res.nil?
114
148
  code = res[0][0]
115
149
  code
116
150
  end
117
151
 
152
+ def trans_type(dmtype)
153
+ case dmtype.to_s
154
+ when 'String'
155
+ return 'ShortText'
156
+ when 'Text'
157
+ return 'Text'
158
+ when 'Float'
159
+ return 'Float'
160
+ when 'Bool'
161
+ return 'Bool'
162
+ when 'Boolean'
163
+ return 'Bool'
164
+ when 'Integer'
165
+ return 'Int32'
166
+ when 'BigDecimal'
167
+ return 'Int64'
168
+ when 'Time'
169
+ return 'Time'
170
+ when /^DataMapper::Types::(.+)$/
171
+ case $1
172
+ when "Boolean"
173
+ return 'Bool'
174
+ when "Serial"
175
+ return 'Int32'
176
+ when "Text"
177
+ return "Text"
178
+ end
179
+ else
180
+ return 'ShortText'
181
+ end
182
+ end
183
+
184
+
118
185
  def create_term_table(table_name, key_prop="ShortText", tokenizer="TokenBigram")
119
186
  res = request "table_create #{table_name} TABLE_PAT_KEY|KEY_NORMALIZE #{key_prop} Void #{tokenizer}"
120
187
  throw "Fale to create term table." unless err_code(res) == 0 || err_code(res) == -22
@@ -159,35 +226,6 @@ module DataMapper
159
226
  [ sort_str, options[:offset], options[:limit] ]
160
227
  end
161
228
 
162
- def trans_type(dmtype)
163
- case dmtype.to_s
164
- when 'String'
165
- return 'ShortText'
166
- when 'Text'
167
- return 'LongText'
168
- when 'Float'
169
- return 'Float'
170
- when 'Bool'
171
- return 'Bool'
172
- when 'Boolean'
173
- return 'Bool'
174
- when 'Integer'
175
- return 'Int32'
176
- when 'BigDecimal'
177
- return 'Int64'
178
- when 'Time'
179
- return 'Time'
180
- when /^DataMapper::Types::(.+)$/
181
- case $1
182
- when "Boolean"
183
- return 'Bool'
184
- when "Serial"
185
- return 'Int32'
186
- end
187
- else
188
- return 'ShortText'
189
- end
190
- end
191
229
  end # class GroongaAdapter::RemoteIndex
192
230
  end # module Adapters
193
231
  end # module DataMapper
@@ -7,3 +7,4 @@ require 'groonga_adapter/remote_result'
7
7
  require 'groonga_adapter/repository_ext'
8
8
  require 'groonga_adapter/model_ext'
9
9
  require 'groonga_adapter/unicode_ext'
10
+ require 'groonga_adapter/jsonparser'
@@ -3,13 +3,13 @@ shared_examples_for 'as is_search plugin' do
3
3
  before(:each) do
4
4
  DataMapper.setup(:default, "sqlite3::memory:")
5
5
  DataMapper.setup(:search, "groonga://#{index_path}")
6
- DataMapper::Logger.new($stderr, :debug)
6
+ # DataMapper::Logger.new($stderr, :debug)
7
7
  Object.send(:remove_const, :Image) if defined?(Image)
8
8
  class ::Image
9
9
  include DataMapper::Resource
10
10
  property :id, Serial
11
11
  property :title, String
12
-
12
+ property :description, Text
13
13
  is :searchable # this defaults to :search repository, you could also do
14
14
  end
15
15
 
@@ -61,4 +61,15 @@ shared_examples_for 'as is_search plugin' do
61
61
  # Story.fulltext_search("John").should == [story, story2] # <--- Crash on local index.
62
62
  Story.fulltext_search("author:@John").should == [story, story2]
63
63
  end
64
+
65
+ it 'should return all result when there is more than 10 result' do
66
+ suffix = (0..10).map {|i| "long description." }
67
+ (0..157).each do |num|
68
+ img = Image.create(:title => "Picture_#{num}", :description => "#{suffix}")
69
+ img.save
70
+ end
71
+ results = Image.search(:title.like => "Picture")
72
+ results.size.should == 158
73
+ end
64
74
  end
75
+
metadata CHANGED
@@ -6,8 +6,8 @@ version: !ruby/object:Gem::Version
6
6
  - 0
7
7
  - 1
8
8
  - 0
9
- - pre
10
- version: 0.1.0.pre
9
+ - pre2
10
+ version: 0.1.0.pre2
11
11
  platform: ruby
12
12
  authors:
13
13
  - hiroyuki
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-04-08 00:00:00 +09:00
18
+ date: 2010-04-15 00:00:00 +09:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -105,6 +105,7 @@ files:
105
105
  - examples/basic.rb
106
106
  - lib/groonga_adapter.rb
107
107
  - lib/groonga_adapter/adapter.rb
108
+ - lib/groonga_adapter/jsonparser.rb
108
109
  - lib/groonga_adapter/local_index.rb
109
110
  - lib/groonga_adapter/model_ext.rb
110
111
  - lib/groonga_adapter/remote_index.rb
@@ -120,7 +121,7 @@ files:
120
121
  - spec/specs/remote_result_spec.rb
121
122
  - spec/specs/search_spec.rb
122
123
  has_rdoc: true
123
- homepage: http://github.com/hryk/dm-groonga-adapter
124
+ homepage: http://hryk.github.com/dm-groonga-adapter
124
125
  licenses: []
125
126
 
126
127
  post_install_message: