rroonga 1.2.9 → 1.3.0
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/Gemfile +1 -0
- data/Rakefile +1 -0
- data/bin/grntest-log-analyze +123 -0
- data/bin/groonga-query-log-extract +117 -0
- data/ext/groonga/rb-grn-accessor.c +7 -5
- data/ext/groonga/rb-grn-array-cursor.c +1 -1
- data/ext/groonga/rb-grn-array.c +34 -44
- data/ext/groonga/rb-grn-column.c +74 -38
- data/ext/groonga/rb-grn-context.c +19 -15
- data/ext/groonga/rb-grn-database.c +47 -42
- data/ext/groonga/rb-grn-double-array-trie-cursor.c +40 -0
- data/ext/groonga/rb-grn-double-array-trie.c +530 -0
- data/ext/groonga/rb-grn-encoding-support.c +1 -1
- data/ext/groonga/rb-grn-encoding.c +1 -1
- data/ext/groonga/rb-grn-exception.c +1 -1
- data/ext/groonga/rb-grn-expression-builder.c +1 -1
- data/ext/groonga/rb-grn-expression.c +63 -51
- data/ext/groonga/rb-grn-fix-size-column.c +7 -7
- data/ext/groonga/rb-grn-hash-cursor.c +1 -1
- data/ext/groonga/rb-grn-hash.c +42 -39
- data/ext/groonga/rb-grn-index-column.c +35 -31
- data/ext/groonga/rb-grn-index-cursor.c +1 -1
- data/ext/groonga/rb-grn-logger.c +23 -18
- data/ext/groonga/rb-grn-object.c +40 -27
- data/ext/groonga/rb-grn-operator.c +1 -1
- data/ext/groonga/rb-grn-patricia-trie-cursor.c +1 -1
- data/ext/groonga/rb-grn-patricia-trie.c +122 -90
- data/ext/groonga/rb-grn-plugin.c +8 -7
- data/ext/groonga/rb-grn-posting.c +1 -1
- data/ext/groonga/rb-grn-procedure.c +1 -1
- data/ext/groonga/rb-grn-query.c +12 -12
- data/ext/groonga/rb-grn-record.c +1 -1
- data/ext/groonga/rb-grn-snippet.c +26 -19
- data/ext/groonga/rb-grn-table-cursor-key-support.c +1 -1
- data/ext/groonga/rb-grn-table-cursor.c +4 -3
- data/ext/groonga/rb-grn-table-key-support.c +23 -23
- data/ext/groonga/rb-grn-table.c +268 -153
- data/ext/groonga/rb-grn-type.c +11 -7
- data/ext/groonga/rb-grn-utils.c +4 -1
- data/ext/groonga/rb-grn-variable-size-column.c +1 -1
- data/ext/groonga/rb-grn-variable.c +2 -2
- data/ext/groonga/rb-grn-view-accessor.c +1 -1
- data/ext/groonga/rb-grn-view-cursor.c +1 -1
- data/ext/groonga/rb-grn-view-record.c +1 -1
- data/ext/groonga/rb-grn-view.c +43 -34
- data/ext/groonga/rb-grn.h +6 -2
- data/ext/groonga/rb-groonga.c +1 -1
- data/lib/groonga.rb +4 -2
- data/lib/groonga/context.rb +16 -41
- data/lib/groonga/dumper.rb +6 -4
- data/lib/groonga/expression-builder.rb +52 -26
- data/lib/groonga/grntest-log.rb +206 -0
- data/lib/groonga/pagination.rb +21 -19
- data/lib/groonga/patricia-trie.rb +7 -10
- data/lib/groonga/posting.rb +1 -1
- data/lib/groonga/query-log.rb +348 -0
- data/lib/groonga/record.rb +47 -143
- data/lib/groonga/schema.rb +679 -406
- data/lib/groonga/view-record.rb +4 -10
- data/rroonga-build.rb +1 -1
- data/test/test-array.rb +25 -4
- data/test/test-column.rb +8 -8
- data/test/test-database.rb +2 -3
- data/test/test-double-array-trie.rb +164 -0
- data/test/test-expression-builder.rb +2 -2
- data/test/test-expression.rb +10 -9
- data/test/test-gqtp.rb +2 -2
- data/test/test-hash.rb +32 -8
- data/test/test-patricia-trie.rb +34 -10
- data/test/test-query-log.rb +258 -0
- data/test/test-record.rb +6 -5
- data/test/test-schema-create-table.rb +8 -0
- data/test/test-schema.rb +491 -234
- data/test/test-table.rb +17 -24
- metadata +123 -100
- data/ext/groonga/Makefile +0 -233
@@ -17,22 +17,19 @@
|
|
17
17
|
|
18
18
|
module Groonga
|
19
19
|
class PatriciaTrie
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
# _text_を走査し、レコードのキーとマッチする部分文字列ごとに
|
24
|
-
# そのレコードが_record_として、その部分文字列が_word_として、
|
20
|
+
# _text_ を走査し、レコードのキーとマッチする部分文字列ごとに
|
21
|
+
# そのレコードが _record_ として、その部分文字列が _word_ として、
|
25
22
|
# ブロックが呼び出される。ブロックから返された文字列が元の部
|
26
23
|
# 分文字列と置換される。全てのヒットに対してのその置換処理が
|
27
24
|
# 行われた文字列が返される。
|
28
25
|
#
|
29
|
-
#
|
26
|
+
# @param options [::Hash] The name and value
|
27
|
+
# pairs. Omitted names are initialized as the default value.
|
28
|
+
# @option options [Proc] :other_text_handler The other_text_handler
|
30
29
|
#
|
31
|
-
#
|
32
|
-
# マッチした部分文字列の前後の文字列を変換するProcを指
|
33
|
-
# 定する。
|
30
|
+
# マッチした部分文字列の前後の文字列を変換するProcを指定する。
|
34
31
|
#
|
35
|
-
#
|
32
|
+
# @example
|
36
33
|
# include ERB::Util
|
37
34
|
# Groonga::Context.default_options = {:encoding => "utf-8"}
|
38
35
|
# words = Groonga::PatriciaTrie.create(:key_type => "ShortText",
|
data/lib/groonga/posting.rb
CHANGED
@@ -52,7 +52,7 @@ module Groonga
|
|
52
52
|
|
53
53
|
# Updates all values.
|
54
54
|
#
|
55
|
-
# @param [Hash] parameters The name and value
|
55
|
+
# @param [::Hash] parameters The name and value
|
56
56
|
# pairs. Omitted names are initialized as the default value.
|
57
57
|
# @option parameters [Integer] :record_id The record_id.
|
58
58
|
# @option parameters [Integer] :section_id The section_id.
|
@@ -0,0 +1,348 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2011 Kouhei Sutou <kou@clear-code.com>
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License version 2.1 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
|
18
|
+
require "English"
|
19
|
+
require "shellwords"
|
20
|
+
require "cgi"
|
21
|
+
|
22
|
+
module Groonga
|
23
|
+
module QueryLog
|
24
|
+
class Command
|
25
|
+
class << self
|
26
|
+
@@registered_commands = {}
|
27
|
+
def register(name, klass)
|
28
|
+
@@registered_commands[name] = klass
|
29
|
+
end
|
30
|
+
|
31
|
+
def parse(input)
|
32
|
+
if input.start_with?("/d/")
|
33
|
+
parse_uri_path(input)
|
34
|
+
else
|
35
|
+
parse_command_line(input)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def parse_uri_path(path)
|
41
|
+
name, parameters_string = path.split(/\?/, 2)
|
42
|
+
parameters = {}
|
43
|
+
if parameters_string
|
44
|
+
parameters_string.split(/&/).each do |parameter_string|
|
45
|
+
key, value = parameter_string.split(/\=/, 2)
|
46
|
+
parameters[key] = CGI.unescape(value)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
name = name.gsub(/\A\/d\//, '')
|
50
|
+
name, output_type = name.split(/\./, 2)
|
51
|
+
parameters["output_type"] = output_type if output_type
|
52
|
+
command_class = @@registered_commands[name] || self
|
53
|
+
command = command_class.new(name, parameters)
|
54
|
+
command.original_format = :uri
|
55
|
+
command
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_command_line(command_line)
|
59
|
+
name, *options = Shellwords.shellwords(command_line)
|
60
|
+
parameters = {}
|
61
|
+
options.each_slice(2) do |key, value|
|
62
|
+
parameters[key.gsub(/\A--/, '')] = value
|
63
|
+
end
|
64
|
+
command_class = @@registered_commands[name] || self
|
65
|
+
command = command_class.new(name, parameters)
|
66
|
+
command.original_format = :command
|
67
|
+
command
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
attr_reader :name, :parameters
|
72
|
+
attr_accessor :original_format
|
73
|
+
def initialize(name, parameters)
|
74
|
+
@name = name
|
75
|
+
@parameters = parameters
|
76
|
+
@original_format = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
def ==(other)
|
80
|
+
other.is_a?(self.class) and
|
81
|
+
@name == other.name and
|
82
|
+
@parameters == other.parameters
|
83
|
+
end
|
84
|
+
|
85
|
+
def uri_format?
|
86
|
+
@original_format == :uri
|
87
|
+
end
|
88
|
+
|
89
|
+
def command_format?
|
90
|
+
@original_format == :command
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_uri_format
|
94
|
+
path = "/d/#{@name}"
|
95
|
+
parameters = @parameters.dup
|
96
|
+
output_type = parameters.delete("output_type")
|
97
|
+
path << ".#{output_type}" if output_type
|
98
|
+
unless parameters.empty?
|
99
|
+
sorted_parameters = parameters.sort_by do |name, _|
|
100
|
+
name.to_s
|
101
|
+
end
|
102
|
+
uri_parameters = sorted_parameters.collect do |name, value|
|
103
|
+
"#{CGI.escape(name)}=#{CGI.escape(value)}"
|
104
|
+
end
|
105
|
+
path << "?"
|
106
|
+
path << uri_parameters.join("&")
|
107
|
+
end
|
108
|
+
path
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_command_format
|
112
|
+
command_line = [@name]
|
113
|
+
sorted_parameters = @parameters.sort_by do |name, _|
|
114
|
+
name.to_s
|
115
|
+
end
|
116
|
+
sorted_parameters.each do |name, value|
|
117
|
+
escaped_value = value.gsub(/[\n"\\]/) do
|
118
|
+
special_character = $MATCH
|
119
|
+
case special_character
|
120
|
+
when "\n"
|
121
|
+
"\\n"
|
122
|
+
else
|
123
|
+
"\\#{special_character}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
command_line << "--#{name}"
|
127
|
+
command_line << "\"#{escaped_value}\""
|
128
|
+
end
|
129
|
+
command_line.join(" ")
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class SelectCommand < Command
|
134
|
+
register("select", self)
|
135
|
+
|
136
|
+
def sortby
|
137
|
+
@parameters["sortby"]
|
138
|
+
end
|
139
|
+
|
140
|
+
def scorer
|
141
|
+
@parameters["scorer"]
|
142
|
+
end
|
143
|
+
|
144
|
+
def query
|
145
|
+
@parameters["query"]
|
146
|
+
end
|
147
|
+
|
148
|
+
def filter
|
149
|
+
@parameters["filter"]
|
150
|
+
end
|
151
|
+
|
152
|
+
def conditions
|
153
|
+
@conditions ||= filter.split(/(?:&&|&!|\|\|)/).collect do |condition|
|
154
|
+
condition = condition.strip
|
155
|
+
condition = condition.gsub(/\A[\s\(]*/, '')
|
156
|
+
condition = condition.gsub(/[\s\)]*\z/, '') unless /\(/ =~ condition
|
157
|
+
condition
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def drilldowns
|
162
|
+
@drilldowns ||= (@parameters["drilldown"] || "").split(/\s*,\s*/)
|
163
|
+
end
|
164
|
+
|
165
|
+
def output_columns
|
166
|
+
@parameters["output_columns"]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class Statistic
|
171
|
+
attr_reader :context_id, :start_time, :raw_command
|
172
|
+
attr_reader :elapsed, :return_code
|
173
|
+
attr_accessor :slow_operation_threshold, :slow_response_threshold
|
174
|
+
def initialize(context_id)
|
175
|
+
@context_id = context_id
|
176
|
+
@start_time = nil
|
177
|
+
@command = nil
|
178
|
+
@raw_command = nil
|
179
|
+
@operations = []
|
180
|
+
@elapsed = nil
|
181
|
+
@return_code = 0
|
182
|
+
@slow_operation_threshold = 0.1
|
183
|
+
@slow_response_threshold = 0.2
|
184
|
+
end
|
185
|
+
|
186
|
+
def start(start_time, command)
|
187
|
+
@start_time = start_time
|
188
|
+
@raw_command = command
|
189
|
+
end
|
190
|
+
|
191
|
+
def finish(elapsed, return_code)
|
192
|
+
@elapsed = elapsed
|
193
|
+
@return_code = return_code
|
194
|
+
end
|
195
|
+
|
196
|
+
def command
|
197
|
+
@command ||= Command.parse(@raw_command)
|
198
|
+
end
|
199
|
+
|
200
|
+
def elapsed_in_seconds
|
201
|
+
nano_seconds_to_seconds(@elapsed)
|
202
|
+
end
|
203
|
+
|
204
|
+
def last_time
|
205
|
+
@start_time + elapsed_in_seconds
|
206
|
+
end
|
207
|
+
|
208
|
+
def slow?
|
209
|
+
elapsed_in_seconds >= @slow_response_threshold
|
210
|
+
end
|
211
|
+
|
212
|
+
def each_operation
|
213
|
+
previous_elapsed = 0
|
214
|
+
ensure_parse_command
|
215
|
+
operation_context_context = {
|
216
|
+
:filter_index => 0,
|
217
|
+
:drilldown_index => 0,
|
218
|
+
}
|
219
|
+
@operations.each_with_index do |operation, i|
|
220
|
+
relative_elapsed = operation[:elapsed] - previous_elapsed
|
221
|
+
relative_elapsed_in_seconds = nano_seconds_to_seconds(relative_elapsed)
|
222
|
+
previous_elapsed = operation[:elapsed]
|
223
|
+
parsed_operation = {
|
224
|
+
:i => i,
|
225
|
+
:elapsed => operation[:elapsed],
|
226
|
+
:elapsed_in_seconds => nano_seconds_to_seconds(operation[:elapsed]),
|
227
|
+
:relative_elapsed => relative_elapsed,
|
228
|
+
:relative_elapsed_in_seconds => relative_elapsed_in_seconds,
|
229
|
+
:name => operation[:name],
|
230
|
+
:context => operation_context(operation[:name],
|
231
|
+
operation_context_context),
|
232
|
+
:n_records => operation[:n_records],
|
233
|
+
:slow? => slow_operation?(relative_elapsed_in_seconds),
|
234
|
+
}
|
235
|
+
yield parsed_operation
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def add_operation(operation)
|
240
|
+
@operations << operation
|
241
|
+
end
|
242
|
+
|
243
|
+
def operations
|
244
|
+
_operations = []
|
245
|
+
each_operation do |operation|
|
246
|
+
_operations << operation
|
247
|
+
end
|
248
|
+
_operations
|
249
|
+
end
|
250
|
+
|
251
|
+
def select_command?
|
252
|
+
command.name == "select"
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
def nano_seconds_to_seconds(nano_seconds)
|
257
|
+
nano_seconds / 1000.0 / 1000.0 / 1000.0
|
258
|
+
end
|
259
|
+
|
260
|
+
def operation_context(label, context)
|
261
|
+
case label
|
262
|
+
when "filter"
|
263
|
+
if @select_command.query and context[:query_used].nil?
|
264
|
+
context[:query_used] = true
|
265
|
+
"query: #{@select_command.query}"
|
266
|
+
else
|
267
|
+
index = context[:filter_index]
|
268
|
+
context[:filter_index] += 1
|
269
|
+
@select_command.conditions[index]
|
270
|
+
end
|
271
|
+
when "sort"
|
272
|
+
@select_command.sortby
|
273
|
+
when "score"
|
274
|
+
@select_command.scorer
|
275
|
+
when "output"
|
276
|
+
@select_command.output_columns
|
277
|
+
when "drilldown"
|
278
|
+
index = context[:drilldown_index]
|
279
|
+
context[:drilldown_index] += 1
|
280
|
+
@select_command.drilldowns[index]
|
281
|
+
else
|
282
|
+
nil
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def ensure_parse_command
|
287
|
+
return unless select_command?
|
288
|
+
@select_command = SelectCommand.parse(@raw_command)
|
289
|
+
end
|
290
|
+
|
291
|
+
def slow_operation?(elapsed)
|
292
|
+
elapsed >= @slow_operation_threshold
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
class Parser
|
297
|
+
def initialize
|
298
|
+
end
|
299
|
+
|
300
|
+
def parse(input, &block)
|
301
|
+
current_statistics = {}
|
302
|
+
input.each_line do |line|
|
303
|
+
case line
|
304
|
+
when /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)\.(\d+)\|(.+?)\|([>:<])/
|
305
|
+
year, month, day, hour, minutes, seconds, micro_seconds =
|
306
|
+
$1, $2, $3, $4, $5, $6, $7
|
307
|
+
context_id = $8
|
308
|
+
type = $9
|
309
|
+
rest = $POSTMATCH.strip
|
310
|
+
time_stamp = Time.local(year, month, day, hour, minutes, seconds,
|
311
|
+
micro_seconds)
|
312
|
+
parse_line(current_statistics,
|
313
|
+
time_stamp, context_id, type, rest, &block)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
private
|
319
|
+
def parse_line(current_statistics,
|
320
|
+
time_stamp, context_id, type, rest, &block)
|
321
|
+
case type
|
322
|
+
when ">"
|
323
|
+
statistic = Statistic.new(context_id)
|
324
|
+
statistic.start(time_stamp, rest)
|
325
|
+
current_statistics[context_id] = statistic
|
326
|
+
when ":"
|
327
|
+
return unless /\A(\d+) (.+)\((\d+)\)/ =~ rest
|
328
|
+
elapsed = $1
|
329
|
+
name = $2
|
330
|
+
n_records = $3.to_i
|
331
|
+
statistic = current_statistics[context_id]
|
332
|
+
return if statistic.nil?
|
333
|
+
statistic.add_operation(:name => name,
|
334
|
+
:elapsed => elapsed.to_i,
|
335
|
+
:n_records => n_records)
|
336
|
+
when "<"
|
337
|
+
return unless /\A(\d+) rc=(\d+)/ =~ rest
|
338
|
+
elapsed = $1
|
339
|
+
return_code = $2
|
340
|
+
statistic = current_statistics.delete(context_id)
|
341
|
+
return if statistic.nil?
|
342
|
+
statistic.finish(elapsed.to_i, return_code.to_i)
|
343
|
+
block.call(statistic)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
data/lib/groonga/record.rb
CHANGED
@@ -21,7 +21,7 @@ module Groonga
|
|
21
21
|
class Record
|
22
22
|
# レコードが所属するテーブル
|
23
23
|
attr_reader :table
|
24
|
-
# _table_の_id_に対応するレコードを作成する。_values_には各
|
24
|
+
# _table_ の _id_ に対応するレコードを作成する。_values_ には各
|
25
25
|
# カラムに設定する値を以下のような形式で指定する。
|
26
26
|
#
|
27
27
|
# [
|
@@ -40,141 +40,96 @@ module Groonga
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
# _record_と_other_が同じテーブルに属していて、さらに、
|
47
|
-
# 同じレコードIDを持つなら+true+を返し、そうでなければ
|
48
|
-
# +false+を返す。
|
43
|
+
# _record_ と _other_ が同じテーブルに属していて、さらに、
|
44
|
+
# 同じレコードIDを持つなら +true+ を返し、そうでなければ
|
45
|
+
# +false+ を返す。
|
49
46
|
def ==(other)
|
50
47
|
self.class == other.class and
|
51
48
|
[table, id] == [other.table, other.id]
|
52
49
|
end
|
53
50
|
|
54
|
-
# call-seq:
|
55
|
-
# record.eql?(other) -> true/false
|
56
|
-
#
|
57
51
|
# Groonga::Record#==と同じ。
|
58
52
|
def eql?(other)
|
59
53
|
self == other
|
60
54
|
end
|
61
55
|
|
62
|
-
# call-seq:
|
63
|
-
# record.hash -> ハッシュ値
|
64
|
-
#
|
65
56
|
# 同じテーブルの同じIDのレコードに対しては常に同じハッシュ
|
66
57
|
# 値を返す。
|
67
58
|
def hash
|
68
59
|
@table.hash ^ @id.hash
|
69
60
|
end
|
70
61
|
|
71
|
-
#
|
72
|
-
# record[column_name] -> 値
|
73
|
-
#
|
74
|
-
# このレコードの_column_name_で指定されたカラムの値を返す。
|
62
|
+
# このレコードの _column_name_ で指定されたカラムの値を返す。
|
75
63
|
def [](column_name)
|
76
64
|
@table.column_value(@id, column_name, :id => true)
|
77
65
|
end
|
78
66
|
|
79
|
-
#
|
80
|
-
# record[column_name] = 値
|
81
|
-
#
|
82
|
-
# このレコードの_column_name_で指定されたカラムの値を設定す
|
67
|
+
# このレコードの _column_name_ で指定されたカラムの値を設定す
|
83
68
|
# る。
|
84
69
|
def []=(column_name, value)
|
85
70
|
@table.set_column_value(@id, column_name, value, :id => true)
|
86
71
|
end
|
87
72
|
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
# このレコードの_column_name_で指定されたカラムの値の最後に
|
92
|
-
# _value_を追加する。
|
73
|
+
# このレコードの _column_name_ で指定されたカラムの値の最後に
|
74
|
+
# _value_ を追加する。
|
93
75
|
def append(column_name, value)
|
94
76
|
column(column_name).append(@id, value)
|
95
77
|
end
|
96
78
|
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
# このレコードの_column_name_で指定されたカラムの値の最初に
|
101
|
-
# _value_を追加する。
|
79
|
+
# このレコードの _column_name_ で指定されたカラムの値の最初に
|
80
|
+
# _value_ を追加する。
|
102
81
|
def prepend(column_name, value)
|
103
82
|
column(column_name).prepend(@id, value)
|
104
83
|
end
|
105
84
|
|
106
|
-
#
|
107
|
-
#
|
108
|
-
#
|
109
|
-
# _record_が所属するテーブルで主キーを使える場合は+true+
|
110
|
-
# を返し、使えない場合は+false+を返す。
|
85
|
+
# _record_ が所属するテーブルで主キーを使える場合は +true+
|
86
|
+
# を返し、使えない場合は +false+ を返す。
|
111
87
|
def support_key?
|
112
88
|
@table.support_key?
|
113
89
|
end
|
114
90
|
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
# 名前が_name_のカラムがレコードの所属するテーブルで定義され
|
119
|
-
# ているなら+true+を返す。
|
91
|
+
# 名前が _name_ のカラムがレコードの所属するテーブルで定義され
|
92
|
+
# ているなら +true+ を返す。
|
120
93
|
def have_column?(name)
|
121
94
|
not @table.column(normalize_column_name(name)).nil?
|
122
95
|
end
|
123
96
|
|
124
|
-
#
|
125
|
-
# record.reference_column?(name) -> true/false
|
126
|
-
#
|
127
|
-
# 名前が_name_のカラムが参照カラムであるなら+true+を返す。
|
97
|
+
# 名前が _name_ のカラムが参照カラムであるなら +true+ を返す。
|
128
98
|
def reference_column?(name)
|
129
99
|
column(name).reference?
|
130
100
|
end
|
131
101
|
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
# 名前が_name_のカラムが索引カラム
|
136
|
-
# (Groonga::IndexColumn)であるなら+true+を返す。
|
102
|
+
# 名前が _name_ のカラムが索引カラム
|
103
|
+
# (Groonga::IndexColumn)であるなら +true+ を返す。
|
137
104
|
def index_column?(name)
|
138
105
|
column(name).index?
|
139
106
|
end
|
140
107
|
|
141
|
-
#
|
142
|
-
# record.vector_column?(name) -> true/false
|
143
|
-
#
|
144
|
-
# 名前が_name_のカラムの値がベクターであるなら+true+を返す。
|
108
|
+
# 名前が _name_ のカラムの値がベクターであるなら +true+ を返す。
|
145
109
|
#
|
146
110
|
# @since: 1.0.5
|
147
111
|
def vector_column?(name)
|
148
112
|
column(name).vector?
|
149
113
|
end
|
150
114
|
|
151
|
-
#
|
152
|
-
# record.scalar_column?(name) -> true/false
|
153
|
-
#
|
154
|
-
# 名前が_name_のカラムの値がスカラーであるなら+true+を返す。
|
115
|
+
# 名前が _name_ のカラムの値がスカラーであるなら +true+ を返す。
|
155
116
|
#
|
156
117
|
# @since: 1.0.5
|
157
118
|
def scalar_column?(name)
|
158
119
|
column(name).scalar?
|
159
120
|
end
|
160
121
|
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
164
|
-
# 名前が_name_のGroonga::IndexColumnのsearchメソッドを呼ぶ。
|
165
|
-
# _query_と_options_はそのメソッドにそのまま渡される。詳しく
|
122
|
+
# 名前が _name_ のGroonga::IndexColumnの search メソッドを呼ぶ。
|
123
|
+
# _query_ と _options_ はそのメソッドにそのまま渡される。詳しく
|
166
124
|
# はGroonga::IndexColumn#searchを参照。
|
167
125
|
def search(name, query, options={})
|
168
126
|
column(name).search(query, options)
|
169
127
|
end
|
170
128
|
|
171
|
-
# call-seq:
|
172
|
-
# record.key -> 主キー
|
173
|
-
#
|
174
129
|
# レコードの主キーを返す。
|
175
130
|
#
|
176
|
-
# _record_が所属するテーブルがGroonga:::Arrayの場合は常
|
177
|
-
#
|
131
|
+
# _record_ が所属するテーブルがGroonga:::Arrayの場合は常
|
132
|
+
# に +nil+ を返す。
|
178
133
|
def key
|
179
134
|
if support_key?
|
180
135
|
@key ||= @table.key(@id)
|
@@ -182,13 +137,9 @@ module Groonga
|
|
182
137
|
nil
|
183
138
|
end
|
184
139
|
end
|
185
|
-
|
186
|
-
# call-seq:
|
187
|
-
# record.record_id -> IDまたは主キー
|
188
|
-
#
|
189
140
|
# レコードを一意に識別するための情報を返す。
|
190
141
|
#
|
191
|
-
# _record_が所属するテーブルがGroonga:::Arrayの場合はID
|
142
|
+
# _record_ が所属するテーブルがGroonga:::Arrayの場合はID
|
192
143
|
# を返し、それ以外の場合は主キーを返す。
|
193
144
|
def record_id
|
194
145
|
if support_key?
|
@@ -198,36 +149,24 @@ module Groonga
|
|
198
149
|
end
|
199
150
|
end
|
200
151
|
|
201
|
-
# call-seq:
|
202
|
-
# record.record_raw_id -> ID
|
203
|
-
#
|
204
152
|
# レコードのIDを返す。
|
205
153
|
def record_raw_id
|
206
154
|
@id
|
207
155
|
end
|
208
156
|
alias_method :id, :record_raw_id
|
209
157
|
|
210
|
-
# call-seq:
|
211
|
-
# record.score -> スコア値
|
212
|
-
#
|
213
158
|
# レコードのスコア値を返す。検索結果として生成されたテーブル
|
214
159
|
# のみに定義される。
|
215
160
|
def score
|
216
161
|
self["_score"]
|
217
162
|
end
|
218
163
|
|
219
|
-
#
|
220
|
-
# record.support_score? -> true/false
|
221
|
-
#
|
222
|
-
# Groonga::Record#scoreが利用できる場合はtrueを
|
164
|
+
# Groonga::Record#scoreが利用できる場合は +true+ を
|
223
165
|
# 返す。
|
224
166
|
def support_score?
|
225
167
|
@table.have_column?("_score") # TODO delegate to Table
|
226
168
|
end
|
227
169
|
|
228
|
-
# call-seq:
|
229
|
-
# record.n_sub_records -> 件数
|
230
|
-
#
|
231
170
|
# 主キーの値が同一であったレコードの件数を返す。検索結果とし
|
232
171
|
# て生成されたテーブルのみに定義される。
|
233
172
|
#
|
@@ -237,60 +176,39 @@ module Groonga
|
|
237
176
|
self["_nsubrecs"]
|
238
177
|
end
|
239
178
|
|
240
|
-
#
|
241
|
-
# record.support_sub_records? -> true/false
|
242
|
-
#
|
243
|
-
# Groonga::Record#n_sub_recordsが利用できる場合はtrueを
|
179
|
+
# Groonga::Record#n_sub_recordsが利用できる場合は +true+ を
|
244
180
|
# 返す。
|
245
181
|
def support_sub_records?
|
246
182
|
@table.support_sub_records?
|
247
183
|
end
|
248
184
|
|
249
|
-
# call-seq:
|
250
|
-
# record.value -> 値
|
251
|
-
#
|
252
185
|
# レコードの値を返す。
|
253
186
|
def value
|
254
187
|
@table.value(@id, :id => true)
|
255
188
|
end
|
256
189
|
|
257
|
-
# call-seq:
|
258
|
-
# record.value = 値
|
259
|
-
#
|
260
190
|
# レコードの値を設定する。既存の値は上書きされる。
|
261
191
|
def value=(value)
|
262
192
|
@table.set_value(@id, value, :id => true)
|
263
193
|
end
|
264
194
|
|
265
|
-
#
|
266
|
-
#
|
267
|
-
#
|
268
|
-
# このレコードの_name_で指定されたカラムの値を_delta_だけ増
|
269
|
-
# 加する。_delta_が+nil+の場合は1増加する。
|
195
|
+
# このレコードの _name_ で指定されたカラムの値を _delta_ だけ増
|
196
|
+
# 加する。 _delta_ が +nil+ の場合は1増加する。
|
270
197
|
def increment!(name, delta=nil)
|
271
198
|
column(name).increment!(@id, delta)
|
272
199
|
end
|
273
200
|
|
274
|
-
#
|
275
|
-
#
|
276
|
-
#
|
277
|
-
# このレコードの_name_で指定されたカラムの値を_delta_だけ減
|
278
|
-
# 少する。_delta_が+nil+の場合は1減少する。
|
201
|
+
# このレコードの _name_ で指定されたカラムの値を _delta_ だけ減
|
202
|
+
# 少する。 _delta_ が +nil+ の場合は1減少する。
|
279
203
|
def decrement!(name, delta=nil)
|
280
204
|
column(name).decrement!(@id, delta)
|
281
205
|
end
|
282
206
|
|
283
|
-
# call-seq:
|
284
|
-
# record.columns -> Groonga::Columnの配列
|
285
|
-
#
|
286
207
|
# レコードが所属するテーブルの全てのカラムを返す。
|
287
208
|
def columns
|
288
209
|
@table.columns
|
289
210
|
end
|
290
211
|
|
291
|
-
# call-seq:
|
292
|
-
# attributes -> Hash
|
293
|
-
#
|
294
212
|
# レコードが所属しているテーブルで定義されているインデックス
|
295
213
|
# 型のカラムでない全カラムを対象とし、カラムの名前をキーとし
|
296
214
|
# たこのレコードのカラムの値のハッシュを返す。
|
@@ -301,36 +219,26 @@ module Groonga
|
|
301
219
|
accessor.build
|
302
220
|
end
|
303
221
|
|
304
|
-
# call-seq:
|
305
|
-
# record.delete
|
306
|
-
#
|
307
222
|
# レコードを削除する。
|
308
223
|
def delete
|
309
224
|
@table.delete(@id)
|
310
225
|
end
|
311
226
|
|
312
|
-
# call-seq:
|
313
|
-
# record.lock(options={})
|
314
|
-
# record.lock(options={}) {...}
|
315
|
-
#
|
316
227
|
# レコードが所属するテーブルをロックする。ロックに失敗した場
|
317
228
|
# 合はGroonga::ResourceDeadlockAvoided例外が発生する。
|
318
229
|
#
|
319
230
|
# ブロックを指定した場合はブロックを抜けたときにunlockする。
|
320
231
|
#
|
321
|
-
#
|
322
|
-
#
|
323
|
-
#
|
324
|
-
#
|
325
|
-
#
|
326
|
-
#
|
232
|
+
# 利用可能な _option_ は以下の通り。
|
233
|
+
# @param [Hash] options The name and value
|
234
|
+
# pairs. Omitted names are initialized as the default value.
|
235
|
+
# @option options [Integer] :timeout The timeout
|
236
|
+
# ロックを獲得できなかった場合は _:timeout_ 秒間ロックの獲得を試みる。
|
237
|
+
# _:timeout_ 秒以内にロックを獲得できなかった場合は例外が発生する。
|
327
238
|
def lock(options={}, &block)
|
328
239
|
@table.lock(options.merge(:id => @id), &block)
|
329
240
|
end
|
330
241
|
|
331
|
-
# call-seq:
|
332
|
-
# record.unlock(options={})
|
333
|
-
#
|
334
242
|
# レコードが所属するテーブルのロックを解除する。
|
335
243
|
#
|
336
244
|
# 利用可能なオプションは現在は無い。
|
@@ -338,9 +246,6 @@ module Groonga
|
|
338
246
|
@table.unlock(options.merge(:id => @id))
|
339
247
|
end
|
340
248
|
|
341
|
-
# call-seq:
|
342
|
-
# record.clear_lock(options={})
|
343
|
-
#
|
344
249
|
# レコードが所属するテーブルのロックを強制的に解除する。
|
345
250
|
#
|
346
251
|
# 利用可能なオプションは現在は無い。
|
@@ -348,25 +253,20 @@ module Groonga
|
|
348
253
|
@table.clear_lock(options.merge(:id => @id))
|
349
254
|
end
|
350
255
|
|
351
|
-
#
|
352
|
-
# record.locked?(options={}) -> true/false
|
353
|
-
#
|
354
|
-
# レコードが所属するテーブルがロックされていれば+true+を返す。
|
256
|
+
# レコードが所属するテーブルがロックされていれば +true+ を返す。
|
355
257
|
#
|
356
258
|
# 利用可能なオプションは現在は無い。
|
357
259
|
def locked?(options={})
|
358
260
|
@table.locked?(options.merge(:id => @id))
|
359
261
|
end
|
360
262
|
|
361
|
-
#
|
362
|
-
# record.valid_id? -> true/false
|
363
|
-
#
|
364
|
-
# レコードが持つIDが有効なIDであれば+true+を返す。
|
263
|
+
# レコードが持つIDが有効なIDであれば +true+ を返す。
|
365
264
|
def valid_id?
|
366
265
|
@table.exist?(@id)
|
367
266
|
end
|
368
267
|
|
369
|
-
|
268
|
+
# @private
|
269
|
+
def methods(include_inherited=true)
|
370
270
|
_methods = super
|
371
271
|
return _methods unless include_inherited
|
372
272
|
columns.each do |column|
|
@@ -377,7 +277,8 @@ module Groonga
|
|
377
277
|
_methods
|
378
278
|
end
|
379
279
|
|
380
|
-
|
280
|
+
# @private
|
281
|
+
def respond_to?(name)
|
381
282
|
super or !@table.column(name.to_s.sub(/=\z/, '')).nil?
|
382
283
|
end
|
383
284
|
|
@@ -395,7 +296,8 @@ module Groonga
|
|
395
296
|
name.to_s
|
396
297
|
end
|
397
298
|
|
398
|
-
|
299
|
+
# @private
|
300
|
+
def column(name)
|
399
301
|
_column = @table.column(normalize_column_name(name))
|
400
302
|
raise NoSuchColumn, "column(#{name.inspect}) is nil" if _column.nil?
|
401
303
|
_column
|
@@ -421,7 +323,8 @@ module Groonga
|
|
421
323
|
end
|
422
324
|
end
|
423
325
|
|
424
|
-
|
326
|
+
# @private
|
327
|
+
class AttributeHashBuilder
|
425
328
|
attr_reader :attributes
|
426
329
|
|
427
330
|
def initialize(root_record)
|
@@ -510,3 +413,4 @@ module Groonga
|
|
510
413
|
end
|
511
414
|
end
|
512
415
|
end
|
416
|
+
|