rroonga 1.3.0 → 1.3.1
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 +33 -2
- data/benchmark/common.rb +2 -2
- data/benchmark/read-write-many-small-items.rb +71 -62
- data/benchmark/write-many-small-items.rb +61 -53
- data/ext/groonga/rb-grn-context.c +23 -5
- data/ext/groonga/rb-grn-index-column.c +2 -6
- data/ext/groonga/rb-grn-operator.c +31 -1
- data/ext/groonga/rb-grn-variable-size-column.c +77 -1
- data/ext/groonga/rb-grn.h +2 -11
- data/ext/groonga/rb-groonga.c +1 -2
- data/lib/groonga/command.rb +169 -0
- data/lib/groonga/context.rb +4 -124
- data/lib/groonga/dumper.rb +10 -8
- data/lib/groonga/record.rb +7 -0
- data/lib/groonga/schema.rb +98 -7
- data/rroonga-build.rb +3 -3
- data/test/{test-context-select.rb → test-command-select.rb} +3 -3
- data/test/test-record.rb +18 -1
- data/test/test-schema-dumper.rb +48 -0
- data/test/test-schema-type.rb +35 -0
- data/test/test-schema.rb +81 -11
- data/test/test-table-select.rb +49 -38
- data/test/test-variable-size-column.rb +30 -0
- metadata +80 -82
- data/ext/groonga/rb-grn-query.c +0 -260
- data/test/test-query.rb +0 -22
@@ -211,13 +211,31 @@ VALUE
|
|
211
211
|
rb_grn_context_rb_string_encode (grn_ctx *context, VALUE rb_string)
|
212
212
|
{
|
213
213
|
#ifdef HAVE_RUBY_ENCODING_H
|
214
|
-
|
214
|
+
int index, to_index;
|
215
|
+
rb_encoding *encoding, *to_encoding;
|
216
|
+
grn_encoding context_encoding;
|
217
|
+
|
218
|
+
context_encoding = context->encoding;
|
219
|
+
if (context->encoding == GRN_ENC_DEFAULT)
|
220
|
+
context->encoding = grn_get_default_encoding();
|
221
|
+
if (context->encoding == GRN_ENC_NONE)
|
222
|
+
return rb_string;
|
223
|
+
|
224
|
+
if (RSTRING_LEN(rb_string) < 0)
|
225
|
+
return rb_string;
|
215
226
|
|
216
227
|
encoding = rb_enc_get(rb_string);
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
228
|
+
to_encoding = rb_grn_encoding_to_ruby_encoding(context_encoding);
|
229
|
+
index = rb_enc_to_index(encoding);
|
230
|
+
to_index = rb_enc_to_index(to_encoding);
|
231
|
+
if (index == to_index)
|
232
|
+
return rb_string;
|
233
|
+
|
234
|
+
if (rb_enc_asciicompat(to_encoding) && rb_enc_str_asciionly_p(rb_string))
|
235
|
+
return rb_string;
|
236
|
+
|
237
|
+
rb_string = rb_str_encode(rb_string, rb_enc_from_encoding(to_encoding),
|
238
|
+
0, Qnil);
|
221
239
|
#endif
|
222
240
|
return rb_string;
|
223
241
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- coding: utf-8; c-file-style: "ruby" -*- */
|
2
2
|
/*
|
3
|
-
Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
|
3
|
+
Copyright (C) 2009-2012 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
|
@@ -453,11 +453,7 @@ rb_grn_index_column_search (int argc, VALUE *argv, VALUE self)
|
|
453
453
|
|
454
454
|
rb_scan_args(argc, argv, "11", &rb_query, &options);
|
455
455
|
|
456
|
-
if (CBOOL2RVAL(rb_obj_is_kind_of(rb_query,
|
457
|
-
grn_query *_query;
|
458
|
-
_query = RVAL2GRNQUERY(rb_query);
|
459
|
-
query = (grn_obj *)_query;
|
460
|
-
} else if (CBOOL2RVAL(rb_obj_is_kind_of(rb_query, rb_cInteger))) {
|
456
|
+
if (CBOOL2RVAL(rb_obj_is_kind_of(rb_query, rb_cInteger))) {
|
461
457
|
grn_id id;
|
462
458
|
id = NUM2UINT(rb_query);
|
463
459
|
GRN_TEXT_SET(context, id_query, &id, sizeof(grn_id));
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- coding: utf-8; c-file-style: "ruby" -*- */
|
2
2
|
/*
|
3
|
-
Copyright (C) 2009-
|
3
|
+
Copyright (C) 2009-2012 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
|
@@ -20,6 +20,36 @@
|
|
20
20
|
|
21
21
|
VALUE rb_mGrnOperator;
|
22
22
|
|
23
|
+
grn_operator
|
24
|
+
rb_grn_operator_from_ruby_object (VALUE rb_operator)
|
25
|
+
{
|
26
|
+
grn_operator operator = GRN_OP_OR;
|
27
|
+
|
28
|
+
if (NIL_P(rb_operator) ||
|
29
|
+
rb_grn_equal_option(rb_operator, "or") ||
|
30
|
+
rb_grn_equal_option(rb_operator, "||")) {
|
31
|
+
operator = GRN_OP_OR;
|
32
|
+
} else if (rb_grn_equal_option(rb_operator, "and") ||
|
33
|
+
rb_grn_equal_option(rb_operator, "+") ||
|
34
|
+
rb_grn_equal_option(rb_operator, "&&")) {
|
35
|
+
operator = GRN_OP_AND;
|
36
|
+
} else if (rb_grn_equal_option(rb_operator, "but") ||
|
37
|
+
rb_grn_equal_option(rb_operator, "not") ||
|
38
|
+
rb_grn_equal_option(rb_operator, "-")) {
|
39
|
+
operator = GRN_OP_BUT;
|
40
|
+
} else if (rb_grn_equal_option(rb_operator, "adjust") ||
|
41
|
+
rb_grn_equal_option(rb_operator, ">")) {
|
42
|
+
operator = GRN_OP_ADJUST;
|
43
|
+
} else {
|
44
|
+
rb_raise(rb_eArgError,
|
45
|
+
"operator should be one of "
|
46
|
+
"[:or, :||, :and, :+, :&&, :but, :not, :-, :adjust, :>]: <%s>",
|
47
|
+
rb_grn_inspect(rb_operator));
|
48
|
+
}
|
49
|
+
|
50
|
+
return operator;
|
51
|
+
}
|
52
|
+
|
23
53
|
void
|
24
54
|
rb_grn_init_operator (VALUE mGrn)
|
25
55
|
{
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- coding: utf-8; c-file-style: "ruby" -*- */
|
2
2
|
/*
|
3
|
-
Copyright (C) 2009 Kouhei Sutou <kou@clear-code.com>
|
3
|
+
Copyright (C) 2009-2011 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
|
@@ -28,6 +28,80 @@ VALUE rb_cGrnVariableSizeColumn;
|
|
28
28
|
* 可変長データ用のカラム。
|
29
29
|
*/
|
30
30
|
|
31
|
+
/*
|
32
|
+
* Document-method: compressed?
|
33
|
+
*
|
34
|
+
* call-seq:
|
35
|
+
* column.compressed? -> boolean
|
36
|
+
* column.compressed?(type) -> boolean
|
37
|
+
*
|
38
|
+
* Returns whether the column is compressed or not. If
|
39
|
+
* @type@ is specified, it returns whether the column is
|
40
|
+
* compressed by @type@ or not.
|
41
|
+
*
|
42
|
+
* @return [Boolean] whether the column is compressed or not.
|
43
|
+
* @param [:zlib, :lzo] type (nil) If @type@ isn't @nil@,
|
44
|
+
* it checks whether specified compressed type is used or
|
45
|
+
* not.
|
46
|
+
* @since 1.3.1
|
47
|
+
*/
|
48
|
+
static VALUE
|
49
|
+
rb_grn_variable_size_column_compressed_p (int argc, VALUE *argv, VALUE self)
|
50
|
+
{
|
51
|
+
RbGrnColumn *rb_grn_column;
|
52
|
+
grn_ctx *context = NULL;
|
53
|
+
grn_obj *column;
|
54
|
+
grn_obj_flags flags;
|
55
|
+
VALUE type;
|
56
|
+
grn_bool compressed_p = GRN_FALSE;
|
57
|
+
grn_bool accept_any_type = GRN_FALSE;
|
58
|
+
grn_bool need_zlib_check = GRN_FALSE;
|
59
|
+
grn_bool need_lzo_check = GRN_FALSE;
|
60
|
+
|
61
|
+
rb_scan_args(argc, argv, "01", &type);
|
62
|
+
|
63
|
+
if (NIL_P(type)) {
|
64
|
+
accept_any_type = GRN_TRUE;
|
65
|
+
} else {
|
66
|
+
if (rb_grn_equal_option(type, "zlib")) {
|
67
|
+
need_zlib_check = GRN_TRUE;
|
68
|
+
} else if (rb_grn_equal_option(type, "lzo")) {
|
69
|
+
need_lzo_check = GRN_TRUE;
|
70
|
+
} else {
|
71
|
+
rb_raise(rb_eArgError,
|
72
|
+
"compressed type should be <:zlib> or <:lzo>: <%s>",
|
73
|
+
rb_grn_inspect(type));
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
rb_grn_column = SELF(self);
|
78
|
+
rb_grn_object_deconstruct(RB_GRN_OBJECT(rb_grn_column), &column, &context,
|
79
|
+
NULL, NULL,
|
80
|
+
NULL, NULL);
|
81
|
+
|
82
|
+
flags = column->header.flags;
|
83
|
+
switch (flags & GRN_OBJ_COMPRESS_MASK) {
|
84
|
+
case GRN_OBJ_COMPRESS_ZLIB:
|
85
|
+
if (accept_any_type || need_zlib_check) {
|
86
|
+
grn_obj support_p;
|
87
|
+
GRN_BOOL_INIT(&support_p, 0);
|
88
|
+
grn_obj_get_info(context, NULL, GRN_INFO_SUPPORT_ZLIB, &support_p);
|
89
|
+
compressed_p = GRN_BOOL_VALUE(&support_p);
|
90
|
+
}
|
91
|
+
break;
|
92
|
+
case GRN_OBJ_COMPRESS_LZO:
|
93
|
+
if (accept_any_type || need_lzo_check) {
|
94
|
+
grn_obj support_p;
|
95
|
+
GRN_BOOL_INIT(&support_p, 0);
|
96
|
+
grn_obj_get_info(context, NULL, GRN_INFO_SUPPORT_LZO, &support_p);
|
97
|
+
compressed_p = GRN_BOOL_VALUE(&support_p);
|
98
|
+
}
|
99
|
+
break;
|
100
|
+
}
|
101
|
+
|
102
|
+
return CBOOL2RVAL(compressed_p);
|
103
|
+
}
|
104
|
+
|
31
105
|
/*
|
32
106
|
* Document-method: defrag
|
33
107
|
*
|
@@ -77,6 +151,8 @@ rb_grn_init_variable_size_column (VALUE mGrn)
|
|
77
151
|
rb_cGrnVariableSizeColumn =
|
78
152
|
rb_define_class_under(mGrn, "VariableSizeColumn", rb_cGrnColumn);
|
79
153
|
|
154
|
+
rb_define_method(rb_cGrnVariableSizeColumn, "compressed?",
|
155
|
+
rb_grn_variable_size_column_compressed_p, -1);
|
80
156
|
rb_define_method(rb_cGrnVariableSizeColumn, "defrag",
|
81
157
|
rb_grn_variable_size_column_defrag, -1);
|
82
158
|
}
|
data/ext/groonga/rb-grn.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- c-file-style: "ruby" -*- */
|
2
2
|
/*
|
3
|
-
Copyright (C) 2009-
|
3
|
+
Copyright (C) 2009-2012 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
|
@@ -72,7 +72,7 @@ RB_GRN_BEGIN_DECLS
|
|
72
72
|
|
73
73
|
#define RB_GRN_MAJOR_VERSION 1
|
74
74
|
#define RB_GRN_MINOR_VERSION 3
|
75
|
-
#define RB_GRN_MICRO_VERSION
|
75
|
+
#define RB_GRN_MICRO_VERSION 1
|
76
76
|
|
77
77
|
#define RB_GRN_QUERY_DEFAULT_MAX_EXPRESSIONS 32
|
78
78
|
|
@@ -227,7 +227,6 @@ RB_GRN_VAR VALUE rb_cGrnAccessor;
|
|
227
227
|
RB_GRN_VAR VALUE rb_cGrnViewAccessor;
|
228
228
|
RB_GRN_VAR VALUE rb_cGrnRecord;
|
229
229
|
RB_GRN_VAR VALUE rb_cGrnViewRecord;
|
230
|
-
RB_GRN_VAR VALUE rb_cGrnQuery;
|
231
230
|
RB_GRN_VAR VALUE rb_cGrnLogger;
|
232
231
|
RB_GRN_VAR VALUE rb_cGrnSnippet;
|
233
232
|
RB_GRN_VAR VALUE rb_cGrnVariable;
|
@@ -270,7 +269,6 @@ void rb_grn_init_accessor (VALUE mGrn);
|
|
270
269
|
void rb_grn_init_view_accessor (VALUE mGrn);
|
271
270
|
void rb_grn_init_record (VALUE mGrn);
|
272
271
|
void rb_grn_init_view_record (VALUE mGrn);
|
273
|
-
void rb_grn_init_query (VALUE mGrn);
|
274
272
|
void rb_grn_init_variable (VALUE mGrn);
|
275
273
|
void rb_grn_init_operator (VALUE mGrn);
|
276
274
|
void rb_grn_init_expression (VALUE mGrn);
|
@@ -555,9 +553,6 @@ VALUE rb_grn_column_expression_builder_build
|
|
555
553
|
#define GRNACCESSOR2RVAL(context, accessor, owner) \
|
556
554
|
(rb_grn_accessor_to_ruby_object(context, accessor, owner))
|
557
555
|
|
558
|
-
#define RVAL2GRNQUERY(object) (rb_grn_query_from_ruby_object(object))
|
559
|
-
#define GRNQUERY2RVAL(context, column)(rb_grn_query_to_ruby_object(context, column))
|
560
|
-
|
561
556
|
#define RVAL2GRNOPERATOR(object) (rb_grn_operator_from_ruby_object(object))
|
562
557
|
|
563
558
|
#define RVAL2GRNLOGGER(object) (rb_grn_logger_from_ruby_object(object))
|
@@ -665,10 +660,6 @@ VALUE rb_grn_index_cursor_to_ruby_object (grn_ctx *context,
|
|
665
660
|
grn_obj *cursor,
|
666
661
|
grn_bool owner);
|
667
662
|
|
668
|
-
grn_query *rb_grn_query_from_ruby_object (VALUE object);
|
669
|
-
VALUE rb_grn_query_to_ruby_object (grn_ctx *context,
|
670
|
-
grn_query *query);
|
671
|
-
|
672
663
|
grn_operator rb_grn_operator_from_ruby_object (VALUE object);
|
673
664
|
|
674
665
|
grn_logger_info *
|
data/ext/groonga/rb-groonga.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/* -*- coding: utf-8; c-file-style: "ruby" -*- */
|
2
2
|
/*
|
3
|
-
Copyright (C) 2009-
|
3
|
+
Copyright (C) 2009-2012 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
|
@@ -138,7 +138,6 @@ Init_groonga (void)
|
|
138
138
|
rb_grn_init_view_accessor(mGrn);
|
139
139
|
rb_grn_init_record(mGrn);
|
140
140
|
rb_grn_init_view_record(mGrn);
|
141
|
-
rb_grn_init_query(mGrn);
|
142
141
|
rb_grn_init_variable(mGrn);
|
143
142
|
rb_grn_init_operator(mGrn);
|
144
143
|
rb_grn_init_expression(mGrn);
|
@@ -0,0 +1,169 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 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
|
+
module Groonga
|
19
|
+
module Command
|
20
|
+
class Builder
|
21
|
+
class << self
|
22
|
+
def escape_value(value)
|
23
|
+
escaped_value = value.to_s.gsub(/"/, '\\"')
|
24
|
+
"\"#{escaped_value}\""
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :command, :arguments
|
29
|
+
def initialize(command, arguments={})
|
30
|
+
@command = command
|
31
|
+
@arguments = arguments
|
32
|
+
end
|
33
|
+
|
34
|
+
def [](key)
|
35
|
+
@arguments[key]
|
36
|
+
end
|
37
|
+
|
38
|
+
def []=(key, value)
|
39
|
+
@arguments[key] = value
|
40
|
+
end
|
41
|
+
|
42
|
+
def build
|
43
|
+
query = "#{@command} "
|
44
|
+
@arguments.each do |key, value|
|
45
|
+
value = value.join(", ") if value.is_a?(::Array)
|
46
|
+
escaped_value = self.class.escape_value(value)
|
47
|
+
query << " --#{key} #{escaped_value}"
|
48
|
+
end
|
49
|
+
query
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class Select
|
54
|
+
def initialize(context, table, options)
|
55
|
+
@context = context
|
56
|
+
@table = table
|
57
|
+
@options = normalize_options(options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def exec
|
61
|
+
request_id = @context.send(query)
|
62
|
+
loop do
|
63
|
+
response_id, result = @context.receive
|
64
|
+
if request_id == response_id
|
65
|
+
drill_down_keys = @options["drilldown"]
|
66
|
+
if drill_down_keys.is_a?(String)
|
67
|
+
drill_down_keys = drill_down_keys.split(/(?:\s+|\s*,\s*)/)
|
68
|
+
end
|
69
|
+
return Result.parse(result, drill_down_keys)
|
70
|
+
end
|
71
|
+
# raise if request_id < response_id
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def normalize_options(options)
|
77
|
+
normalized_options = {}
|
78
|
+
options.each do |key, value|
|
79
|
+
normalized_options[normalize_option_name(key)] = value
|
80
|
+
end
|
81
|
+
normalized_options
|
82
|
+
end
|
83
|
+
|
84
|
+
def normalize_option_name(name)
|
85
|
+
name = name.to_s.gsub(/-/, "_").gsub(/drill_down/, "drilldown")
|
86
|
+
name.gsub(/sort_by/, 'sortby')
|
87
|
+
end
|
88
|
+
|
89
|
+
def query
|
90
|
+
if @table.is_a?(String)
|
91
|
+
table_name = @table
|
92
|
+
else
|
93
|
+
table_name = @table.name
|
94
|
+
end
|
95
|
+
builder = Builder.new("select", @options.merge(:table => table_name))
|
96
|
+
builder.build
|
97
|
+
end
|
98
|
+
|
99
|
+
class Result < Struct.new(:n_hits, :columns, :values, :drill_down)
|
100
|
+
class << self
|
101
|
+
def parse(json, drill_down_keys)
|
102
|
+
select_result, *drill_down_results = JSON.parse(json)
|
103
|
+
result = new
|
104
|
+
n_hits, columns, values = extract_result(select_result)
|
105
|
+
result.n_hits = n_hits
|
106
|
+
result.columns = columns
|
107
|
+
result.values = values
|
108
|
+
if drill_down_results
|
109
|
+
result.drill_down = parse_drill_down_results(drill_down_results,
|
110
|
+
drill_down_keys)
|
111
|
+
end
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
def create_records(columns, values)
|
116
|
+
records = []
|
117
|
+
values.each do |value|
|
118
|
+
record = {}
|
119
|
+
columns.each_with_index do |(name, type), i|
|
120
|
+
record[name] = convert_value(value[i], type)
|
121
|
+
end
|
122
|
+
records << record
|
123
|
+
end
|
124
|
+
records
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
def parse_drill_down_results(results, keys)
|
129
|
+
named_results = {}
|
130
|
+
results.each_with_index do |drill_down, i|
|
131
|
+
n_hits, columns, values = extract_result(drill_down)
|
132
|
+
drill_down_result = DrillDownResult.new
|
133
|
+
drill_down_result.n_hits = n_hits
|
134
|
+
drill_down_result.columns = columns
|
135
|
+
drill_down_result.values = values
|
136
|
+
named_results[keys[i]] = drill_down_result
|
137
|
+
end
|
138
|
+
named_results
|
139
|
+
end
|
140
|
+
|
141
|
+
def extract_result(result)
|
142
|
+
meta_data, columns, *values = result
|
143
|
+
n_hits, = meta_data
|
144
|
+
[n_hits, columns, values]
|
145
|
+
end
|
146
|
+
|
147
|
+
def convert_value(value, type)
|
148
|
+
case type
|
149
|
+
when "Time"
|
150
|
+
Time.at(value)
|
151
|
+
else
|
152
|
+
value
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def records
|
158
|
+
@records ||= self.class.create_records(columns, values)
|
159
|
+
end
|
160
|
+
|
161
|
+
class DrillDownResult < Struct.new(:n_hits, :columns, :values)
|
162
|
+
def records
|
163
|
+
@records ||= Result.create_records(columns, values)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
data/lib/groonga/context.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
#
|
3
|
-
# Copyright (C) 2010-
|
3
|
+
# Copyright (C) 2010-2012 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
|
@@ -15,6 +15,8 @@
|
|
15
15
|
# License along with this library; if not, write to the Free Software
|
16
16
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
17
|
|
18
|
+
require "groonga/command"
|
19
|
+
|
18
20
|
module Groonga
|
19
21
|
class Context
|
20
22
|
# _path_ にある既存のデータベースを開く。ブロックを指定した場
|
@@ -70,130 +72,8 @@ module Groonga
|
|
70
72
|
# @option options [Array] XXX TODO
|
71
73
|
# TODO
|
72
74
|
def select(table, options={})
|
73
|
-
select =
|
75
|
+
select = Command::Select.new(self, table, options)
|
74
76
|
select.exec
|
75
77
|
end
|
76
|
-
|
77
|
-
class SelectResult < Struct.new(:n_hits, :columns, :values,
|
78
|
-
:drill_down)
|
79
|
-
class << self
|
80
|
-
def parse(json, drill_down_keys)
|
81
|
-
select_result, *drill_down_results = JSON.parse(json)
|
82
|
-
result = new
|
83
|
-
n_hits, columns, values = extract_result(select_result)
|
84
|
-
result.n_hits = n_hits
|
85
|
-
result.columns = columns
|
86
|
-
result.values = values
|
87
|
-
if drill_down_results
|
88
|
-
result.drill_down = parse_drill_down_results(drill_down_results,
|
89
|
-
drill_down_keys)
|
90
|
-
end
|
91
|
-
result
|
92
|
-
end
|
93
|
-
|
94
|
-
def create_records(columns, values)
|
95
|
-
records = []
|
96
|
-
values.each do |value|
|
97
|
-
record = {}
|
98
|
-
columns.each_with_index do |(name, type), i|
|
99
|
-
record[name] = convert_value(value[i], type)
|
100
|
-
end
|
101
|
-
records << record
|
102
|
-
end
|
103
|
-
records
|
104
|
-
end
|
105
|
-
|
106
|
-
private
|
107
|
-
def parse_drill_down_results(results, keys)
|
108
|
-
named_results = {}
|
109
|
-
results.each_with_index do |drill_down, i|
|
110
|
-
n_hits, columns, values = extract_result(drill_down)
|
111
|
-
drill_down_result = DrillDownResult.new
|
112
|
-
drill_down_result.n_hits = n_hits
|
113
|
-
drill_down_result.columns = columns
|
114
|
-
drill_down_result.values = values
|
115
|
-
named_results[keys[i]] = drill_down_result
|
116
|
-
end
|
117
|
-
named_results
|
118
|
-
end
|
119
|
-
|
120
|
-
def extract_result(result)
|
121
|
-
meta_data, columns, *values = result
|
122
|
-
n_hits, = meta_data
|
123
|
-
[n_hits, columns, values]
|
124
|
-
end
|
125
|
-
|
126
|
-
def convert_value(value, type)
|
127
|
-
case type
|
128
|
-
when "Time"
|
129
|
-
Time.at(value)
|
130
|
-
else
|
131
|
-
value
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def records
|
137
|
-
@records ||= self.class.create_records(columns, values)
|
138
|
-
end
|
139
|
-
|
140
|
-
class DrillDownResult < Struct.new(:n_hits, :columns, :values)
|
141
|
-
def records
|
142
|
-
@records ||= SelectResult.create_records(columns, values)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
class SelectCommand
|
148
|
-
def initialize(context, table, options)
|
149
|
-
@context = context
|
150
|
-
@table = table
|
151
|
-
@options = normalize_options(options)
|
152
|
-
end
|
153
|
-
|
154
|
-
def exec
|
155
|
-
request_id = @context.send(query)
|
156
|
-
loop do
|
157
|
-
response_id, result = @context.receive
|
158
|
-
if request_id == response_id
|
159
|
-
drill_down_keys = @options["drilldown"]
|
160
|
-
if drill_down_keys.is_a?(String)
|
161
|
-
drill_down_keys = drill_down_keys.split(/(?:\s+|\s*,\s*)/)
|
162
|
-
end
|
163
|
-
return SelectResult.parse(result, drill_down_keys)
|
164
|
-
end
|
165
|
-
# raise if request_id < response_id
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
private
|
170
|
-
def normalize_options(options)
|
171
|
-
normalized_options = {}
|
172
|
-
options.each do |key, value|
|
173
|
-
normalized_options[normalize_option_name(key)] = value
|
174
|
-
end
|
175
|
-
normalized_options
|
176
|
-
end
|
177
|
-
|
178
|
-
def normalize_option_name(name)
|
179
|
-
name = name.to_s.gsub(/-/, "_").gsub(/drill_down/, "drilldown")
|
180
|
-
name.gsub(/sort_by/, 'sortby')
|
181
|
-
end
|
182
|
-
|
183
|
-
def query
|
184
|
-
if @table.is_a?(String)
|
185
|
-
table_name = @table
|
186
|
-
else
|
187
|
-
table_name = @table.name
|
188
|
-
end
|
189
|
-
_query = "select #{table_name}"
|
190
|
-
@options.each do |key, value|
|
191
|
-
value = value.join(", ") if value.is_a?(::Array)
|
192
|
-
escaped_value = value.to_s.gsub(/"/, '\\"')
|
193
|
-
_query << " --#{key} \"#{escaped_value}\""
|
194
|
-
end
|
195
|
-
_query
|
196
|
-
end
|
197
|
-
end
|
198
78
|
end
|
199
79
|
end
|