groonga-client 0.5.4 → 0.5.5
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.
- checksums.yaml +4 -4
- data/bin/groonga-client +0 -6
- data/bin/groonga-client-index-check +24 -0
- data/doc/text/news.md +11 -0
- data/groonga-client.gemspec +1 -1
- data/lib/groonga/client/command-line/groonga-client-index-check.rb +190 -0
- data/lib/groonga/client/command-line/groonga-client-index-recreate.rb +23 -137
- data/lib/groonga/client/command-line/groonga-client.rb +11 -73
- data/lib/groonga/client/command-line/parser.rb +111 -0
- data/lib/groonga/client/command-line/runner.rb +122 -0
- data/lib/groonga/client/protocol/http/synchronous.rb +22 -1
- data/lib/groonga/client/response/column-list.rb +10 -0
- data/lib/groonga/client/version.rb +1 -1
- data/test/command-line/helper.rb +87 -0
- data/test/command-line/test-index-check.rb +292 -0
- data/test/command-line/test-index-recreate.rb +4 -63
- data/test/response/test-column-list.rb +54 -0
- metadata +37 -28
@@ -14,26 +14,19 @@
|
|
14
14
|
# License along with this library; if not, write to the Free Software
|
15
15
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
16
|
|
17
|
-
require "optparse"
|
18
17
|
require "json"
|
19
18
|
require "securerandom"
|
20
19
|
|
21
|
-
require "groonga/client"
|
22
|
-
|
23
20
|
require "groonga/command/parser"
|
24
21
|
|
22
|
+
require "groonga/client"
|
23
|
+
require "groonga/client/command-line/parser"
|
24
|
+
|
25
25
|
module Groonga
|
26
26
|
class Client
|
27
27
|
module CommandLine
|
28
28
|
class GroongaClient
|
29
29
|
def initialize
|
30
|
-
@url = nil
|
31
|
-
@protocol = :http
|
32
|
-
@host = "localhost"
|
33
|
-
@port = nil
|
34
|
-
|
35
|
-
@read_timeout = Client::Default::READ_TIMEOUT
|
36
|
-
|
37
30
|
@chunk = false
|
38
31
|
|
39
32
|
@runner_options = {
|
@@ -42,16 +35,13 @@ module Groonga
|
|
42
35
|
}
|
43
36
|
end
|
44
37
|
|
45
|
-
def run(
|
46
|
-
|
38
|
+
def run(arguments)
|
39
|
+
parser = Parser.new
|
40
|
+
command_file_paths = parser.parse(arguments) do |option_parser|
|
41
|
+
parse_command_line(option_parser)
|
42
|
+
end
|
47
43
|
|
48
|
-
|
49
|
-
:protocol => @protocol,
|
50
|
-
:host => @host,
|
51
|
-
:port => @port,
|
52
|
-
:read_timeout => @read_timeout,
|
53
|
-
:chunk => @chunk,
|
54
|
-
:backend => :synchronous) do |client|
|
44
|
+
parser.open_client(:chunk => @chunk) do |client|
|
55
45
|
runner = Runner.new(client, @runner_options)
|
56
46
|
|
57
47
|
if command_file_paths.empty?
|
@@ -79,48 +69,11 @@ module Groonga
|
|
79
69
|
end
|
80
70
|
|
81
71
|
private
|
82
|
-
def parse_command_line(
|
83
|
-
parser = OptionParser.new
|
84
|
-
parser.version = VERSION
|
72
|
+
def parse_command_line(parser)
|
85
73
|
parser.banner += " GROONGA_COMMAND_FILE1 GROONGA_COMMAND_FILE2 ..."
|
86
74
|
|
87
75
|
parser.separator("")
|
88
|
-
|
89
|
-
parser.separator("Connection:")
|
90
|
-
|
91
|
-
parser.on("--url=URL",
|
92
|
-
"URL to connect to Groonga server.",
|
93
|
-
"If this option is specified,",
|
94
|
-
"--protocol, --host and --port are ignored.") do |url|
|
95
|
-
@url = url
|
96
|
-
end
|
97
|
-
|
98
|
-
available_protocols = [:http, :gqtp]
|
99
|
-
parser.on("--protocol=PROTOCOL", [:http, :gqtp],
|
100
|
-
"Protocol to connect to Groonga server.",
|
101
|
-
"[#{available_protocols.join(", ")}]",
|
102
|
-
"(#{@protocol})") do |protocol|
|
103
|
-
@protocol = protocol
|
104
|
-
end
|
105
|
-
|
106
|
-
parser.on("--host=HOST",
|
107
|
-
"Groonga server to be connected.",
|
108
|
-
"(#{@host})") do |host|
|
109
|
-
@host = host
|
110
|
-
end
|
111
|
-
|
112
|
-
parser.on("--port=PORT", Integer,
|
113
|
-
"Port number of Groonga server to be connected.",
|
114
|
-
"(auto)") do |port|
|
115
|
-
@port = port
|
116
|
-
end
|
117
|
-
|
118
|
-
parser.on("--read-timeout=TIMEOUT", Integer,
|
119
|
-
"Timeout on reading response from Groonga server.",
|
120
|
-
"You can disable timeout by specifying -1.",
|
121
|
-
"(#{@read_timeout})") do |timeout|
|
122
|
-
@read_timeout = timeout
|
123
|
-
end
|
76
|
+
parser.separator("Request:")
|
124
77
|
|
125
78
|
parser.on("--split-load-chunk-size=SIZE", Integer,
|
126
79
|
"Split a large load to small loads.",
|
@@ -142,21 +95,6 @@ module Groonga
|
|
142
95
|
"(#{@chunk})") do |boolean|
|
143
96
|
@chunk = boolean
|
144
97
|
end
|
145
|
-
|
146
|
-
command_file_paths = parser.parse(argv)
|
147
|
-
|
148
|
-
@port ||= default_port(@protocol)
|
149
|
-
|
150
|
-
command_file_paths
|
151
|
-
end
|
152
|
-
|
153
|
-
def default_port(protocol)
|
154
|
-
case protocol
|
155
|
-
when :http
|
156
|
-
10041
|
157
|
-
when :gqtp
|
158
|
-
10043
|
159
|
-
end
|
160
98
|
end
|
161
99
|
|
162
100
|
class Runner
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# Copyright (C) 2015-2017 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License as published by the Free Software Foundation; either
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this library; if not, write to the Free Software
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
|
+
|
17
|
+
require "optparse"
|
18
|
+
|
19
|
+
require "groonga/client"
|
20
|
+
|
21
|
+
module Groonga
|
22
|
+
class Client
|
23
|
+
module CommandLine
|
24
|
+
class Parser
|
25
|
+
def initialize(options={})
|
26
|
+
@url = nil
|
27
|
+
@protocol = :http
|
28
|
+
@host = "localhost"
|
29
|
+
@port = nil
|
30
|
+
|
31
|
+
@read_timeout = options[:read_timeout] || Client::Default::READ_TIMEOUT
|
32
|
+
end
|
33
|
+
|
34
|
+
def parse(arguments)
|
35
|
+
parser = OptionParser.new
|
36
|
+
parser.version = VERSION
|
37
|
+
|
38
|
+
parser.separator("")
|
39
|
+
|
40
|
+
parser.separator("Connection:")
|
41
|
+
|
42
|
+
parser.on("--url=URL",
|
43
|
+
"URL to connect to Groonga server.",
|
44
|
+
"If this option is specified,",
|
45
|
+
"--protocol, --host and --port are ignored.") do |url|
|
46
|
+
@url = url
|
47
|
+
end
|
48
|
+
|
49
|
+
available_protocols = [:http, :gqtp]
|
50
|
+
parser.on("--protocol=PROTOCOL", [:http, :gqtp],
|
51
|
+
"Protocol to connect to Groonga server.",
|
52
|
+
"[#{available_protocols.join(", ")}]",
|
53
|
+
"(#{@protocol})") do |protocol|
|
54
|
+
@protocol = protocol
|
55
|
+
end
|
56
|
+
|
57
|
+
parser.on("--host=HOST",
|
58
|
+
"Groonga server to be connected.",
|
59
|
+
"(#{@host})") do |host|
|
60
|
+
@host = host
|
61
|
+
end
|
62
|
+
|
63
|
+
parser.on("--port=PORT", Integer,
|
64
|
+
"Port number of Groonga server to be connected.",
|
65
|
+
"(auto)") do |port|
|
66
|
+
@port = port
|
67
|
+
end
|
68
|
+
|
69
|
+
parser.on("--read-timeout=TIMEOUT", Integer,
|
70
|
+
"Timeout on reading response from Groonga server.",
|
71
|
+
"You can disable timeout by specifying -1.",
|
72
|
+
"(#{@read_timeout})") do |timeout|
|
73
|
+
@read_timeout = timeout
|
74
|
+
end
|
75
|
+
|
76
|
+
yield(parser)
|
77
|
+
|
78
|
+
rest = parser.parse(arguments)
|
79
|
+
|
80
|
+
@port ||= default_port(@protocol)
|
81
|
+
|
82
|
+
rest
|
83
|
+
end
|
84
|
+
|
85
|
+
def open_client(options={})
|
86
|
+
default_options = {
|
87
|
+
:url => @url,
|
88
|
+
:protocol => @protocol,
|
89
|
+
:host => @host,
|
90
|
+
:port => @port,
|
91
|
+
:read_timeout => @read_timeout,
|
92
|
+
:backend => :synchronous,
|
93
|
+
}
|
94
|
+
Client.open(default_options.merge(options)) do |client|
|
95
|
+
yield(client)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
def default_port(protocol)
|
101
|
+
case protocol
|
102
|
+
when :http
|
103
|
+
10041
|
104
|
+
when :gqtp
|
105
|
+
10043
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# Copyright (C) 2017 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License as published by the Free Software Foundation; either
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this library; if not, write to the Free Software
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
|
+
|
17
|
+
module Groonga
|
18
|
+
class Client
|
19
|
+
module CommandLine
|
20
|
+
class Runner
|
21
|
+
def initialize(client)
|
22
|
+
@client = client
|
23
|
+
end
|
24
|
+
|
25
|
+
def run(&block)
|
26
|
+
catch do |tag|
|
27
|
+
@abort_tag = tag
|
28
|
+
run_internal(&block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def abort_run(message)
|
34
|
+
$stderr.puts(message)
|
35
|
+
throw(@abort_tag, false)
|
36
|
+
end
|
37
|
+
|
38
|
+
def execute_command(name, arguments={})
|
39
|
+
response = @client.execute(name, arguments)
|
40
|
+
unless response.success?
|
41
|
+
abort_run("Failed to run #{name}: #{response.inspect}")
|
42
|
+
end
|
43
|
+
response
|
44
|
+
end
|
45
|
+
|
46
|
+
def config_get(key)
|
47
|
+
execute_command(:config_get, :key => key).body
|
48
|
+
end
|
49
|
+
|
50
|
+
def config_set(key, value)
|
51
|
+
execute_command(:config_set, :key => key, :value => value).body
|
52
|
+
end
|
53
|
+
|
54
|
+
def object_exist?(name)
|
55
|
+
execute_command(:object_exist, :name => name).body
|
56
|
+
end
|
57
|
+
|
58
|
+
def table_list
|
59
|
+
execute_command(:table_list)
|
60
|
+
end
|
61
|
+
|
62
|
+
def column_list(table)
|
63
|
+
execute_command(:column_list, :table => table)
|
64
|
+
end
|
65
|
+
|
66
|
+
def column_create(table_name, name, flags, type, source)
|
67
|
+
execute_command(:column_create,
|
68
|
+
:table => table_name,
|
69
|
+
:name => name,
|
70
|
+
:flags => flags,
|
71
|
+
:type => type,
|
72
|
+
:source => source).body
|
73
|
+
end
|
74
|
+
|
75
|
+
def column_create_similar(table_name, column_name, base_column_name)
|
76
|
+
if object_exist?(:schema)
|
77
|
+
info = execute_command(:schema)["#{table_name}.#{base_column_name}"]
|
78
|
+
arguments = info.command.arguments.merge("name" => column_name)
|
79
|
+
execute_command(:column_create, arguments).body
|
80
|
+
else
|
81
|
+
base_column = column_list(table_name).find do |column|
|
82
|
+
column.name == base_column_name
|
83
|
+
end
|
84
|
+
range = base_column.range
|
85
|
+
source_columns = base_column.sources.collect do |source|
|
86
|
+
if source.include?(".")
|
87
|
+
source.split(".", 2)[1]
|
88
|
+
else
|
89
|
+
"_key"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
flags = base_column.flags.dup
|
93
|
+
flags.delete("PERSISTENT")
|
94
|
+
column_create(table_name,
|
95
|
+
column_name,
|
96
|
+
flags.join("|"),
|
97
|
+
range,
|
98
|
+
source_columns.join(","))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def column_remove(table, column)
|
103
|
+
execute_command(:column_remove,
|
104
|
+
:table => table,
|
105
|
+
:name => column).body
|
106
|
+
end
|
107
|
+
|
108
|
+
def column_rename(table, name, new_name)
|
109
|
+
execute_command(:column_rename,
|
110
|
+
:table => table,
|
111
|
+
:name => name,
|
112
|
+
:new_name => new_name).body
|
113
|
+
end
|
114
|
+
|
115
|
+
def select(table, arguments={})
|
116
|
+
execute_command(:select,
|
117
|
+
arguments.merge(:table => table))
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -27,6 +27,27 @@ module Groonga
|
|
27
27
|
module Protocol
|
28
28
|
class HTTP
|
29
29
|
class Synchronous
|
30
|
+
# TODO: Workaround to disable retry in net/http.
|
31
|
+
class HTTPClient < Net::HTTP
|
32
|
+
class ReadTimeout < StandardError
|
33
|
+
end
|
34
|
+
|
35
|
+
module ReadTimeoutConvertable
|
36
|
+
def rbuf_fill
|
37
|
+
begin
|
38
|
+
super
|
39
|
+
rescue Net::ReadTimeout => error
|
40
|
+
raise ReadTimeout, error.message, error.backtrace
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def on_connect
|
47
|
+
@socket.extend(ReadTimeoutConvertable)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
30
51
|
include PathResolvable
|
31
52
|
|
32
53
|
def initialize(url, options={})
|
@@ -36,7 +57,7 @@ module Groonga
|
|
36
57
|
|
37
58
|
def send(command)
|
38
59
|
begin
|
39
|
-
|
60
|
+
HTTPClient.start(@url.host, @url.port, start_options) do |http|
|
40
61
|
http.read_timeout = read_timeout
|
41
62
|
response = send_request(http, command)
|
42
63
|
case response
|
@@ -64,6 +64,14 @@ module Groonga
|
|
64
64
|
:domain,
|
65
65
|
:range,
|
66
66
|
:source)
|
67
|
+
# @return [String]
|
68
|
+
# The column name with table name such as `TABLE.COLUMN`.
|
69
|
+
#
|
70
|
+
# @since 0.5.4
|
71
|
+
def full_name
|
72
|
+
"#{domain}.#{name}"
|
73
|
+
end
|
74
|
+
|
67
75
|
# @return [::Array<String>]
|
68
76
|
# The flag names of the column.
|
69
77
|
#
|
@@ -95,6 +103,8 @@ module Groonga
|
|
95
103
|
def index?
|
96
104
|
flags.include?("COLUMN_INDEX")
|
97
105
|
end
|
106
|
+
|
107
|
+
alias_method :sources, :source
|
98
108
|
end
|
99
109
|
end
|
100
110
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# Copyright (C) 2017 Kouhei Sutou <kou@clear-code.com>
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License as published by the Free Software Foundation; either
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this library; if not, write to the Free Software
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
|
+
|
17
|
+
require "groonga/command/parser"
|
18
|
+
|
19
|
+
require "groonga/client"
|
20
|
+
require "groonga/client/test-helper"
|
21
|
+
|
22
|
+
module CommandLineTestHelper
|
23
|
+
def groonga_url
|
24
|
+
@groonga_server_runner.url.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
def open_client
|
28
|
+
Groonga::Client.open(:url => groonga_url) do |client|
|
29
|
+
yield(client)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def restore(commands)
|
34
|
+
open_client do |client|
|
35
|
+
values = nil
|
36
|
+
Groonga::Command::Parser.parse(commands) do |event, *args|
|
37
|
+
case event
|
38
|
+
when :on_command
|
39
|
+
command, = args
|
40
|
+
response = client.execute(command)
|
41
|
+
unless response.success?
|
42
|
+
raise Groonga::Client::Request::ErrorResponse.new(response)
|
43
|
+
end
|
44
|
+
when :on_load_start
|
45
|
+
command, = args
|
46
|
+
values = []
|
47
|
+
when :on_load_columns
|
48
|
+
command, columns = args
|
49
|
+
command[:columns] ||= columns.join(",")
|
50
|
+
when :on_load_value
|
51
|
+
command, value = args
|
52
|
+
values << value
|
53
|
+
when :on_load_complete
|
54
|
+
command, = args
|
55
|
+
command[:values] ||= JSON.generate(values)
|
56
|
+
response = client.execute(command)
|
57
|
+
unless response.success?
|
58
|
+
raise Groonga::Client::Request::ErrorResponse.new(response)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
p [:unhandled_event, event, *args]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def dump
|
68
|
+
open_client do |client|
|
69
|
+
client.dump.body
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def capture_outputs
|
74
|
+
begin
|
75
|
+
stdout, $stdout = $stdout, StringIO.new
|
76
|
+
stderr, $stderr = $stderr, StringIO.new
|
77
|
+
result = yield
|
78
|
+
[
|
79
|
+
result,
|
80
|
+
$stdout.string,
|
81
|
+
$stderr.string,
|
82
|
+
]
|
83
|
+
ensure
|
84
|
+
$stdout, $stderr = stdout, stderr
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|