groonga-client 0.3.3 → 0.3.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 07f89351f5ba7dc1fbfd0b03c350a124af15dd07
4
- data.tar.gz: 0e428a4ca114c09cf9d536f59faa1aa89bfb09db
3
+ metadata.gz: f47d1a05d48212d7bad001fb9b5a1bfe74f40edc
4
+ data.tar.gz: 95b2962aa8532fa2a74e617779abed394f05de12
5
5
  SHA512:
6
- metadata.gz: 38dff0be4468d31c5afe7b8c0597d6c356b95ef8f8b322f726348bfa32a4568bd3dbc436a856f1939e8aa403a003e67930edd9c8f1dffb05ccb747f6f1a41c2a
7
- data.tar.gz: b70ced387a66aafc5a7cca4444e337883790af77ea06520abf1f38cf87d7b9f981a88889aeb89db9ce2d189678a5a8deb72be36936611e455966645d157051a0
6
+ metadata.gz: fd6abe205934d99203e8b87d37ec5e3ae4586e0705f998a07a6d5735b1e3d5f13c7f8ad10f412ab24587c82808417c08eea7c16c9f90297f0a30c078ae8283ea
7
+ data.tar.gz: 10b410ebf59503342ed22563a7ecc1ff90f7be430c8561acda6e846b8170a5c534201e6d88f6a22e3dcde56445a4a876d7203b2d875d365f563c918fe8ed4c65
data/doc/text/news.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # NEWS
2
2
 
3
+ ## 0.3.4 - 2016-12-13
4
+
5
+ ### Improvements
6
+
7
+ * Added request interface from groonga-client-rails.
8
+ * Added `Groonga::Client::Response::Schema::Index#full_text_searchable?`.
9
+ * Added `Groonga::Client::Response::Schema::Column#have_full_text_search_index?`.
10
+ * Added `Groonga::Client::Response::Schema::Table#have_full_text_search_index?`.
11
+ * Added `Groonga::Client::Response::Select#slices`.
12
+ * Added test helper from groonga-client-rails.
13
+ * Added `Groonga::Client::Response#size` for Kaminari.
14
+ * Added enumrable interface for `Groonga::Client::Response::Select`.
15
+
3
16
  ## 0.3.3 - 2016-12-07
4
17
 
5
18
  ### Improvements
@@ -23,7 +23,7 @@ require "groonga/client/command"
23
23
  require "groonga/client/empty-request"
24
24
  require "groonga/client/protocol/gqtp"
25
25
  require "groonga/client/protocol/http"
26
- require "groonga/client/script-syntax"
26
+ require "groonga/client/request"
27
27
 
28
28
  module Groonga
29
29
  class Client
@@ -0,0 +1,22 @@
1
+ # Copyright (C) 2016 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/client/script-syntax"
18
+
19
+ require "groonga/client/request/base"
20
+ require "groonga/client/request/error"
21
+
22
+ require "groonga/client/request/select"
@@ -0,0 +1,174 @@
1
+ # Copyright (C) 2016 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 Request
20
+ class Base
21
+ def initialize(parameters=nil, extensions=[])
22
+ @parameters = parameters
23
+ @extensions = extensions
24
+ extend(*@extensions) unless @extensions.empty?
25
+ end
26
+
27
+ def response
28
+ @reponse ||= create_response
29
+ end
30
+
31
+ def parameter(name, value)
32
+ add_parameter(OverwriteMerger,
33
+ RequestParameter.new(name, value))
34
+ end
35
+
36
+ def to_parameters
37
+ if @parameters.nil?
38
+ {}
39
+ else
40
+ @parameters.to_parameters
41
+ end
42
+ end
43
+
44
+ def extensions(*modules, &block)
45
+ modules << Module.new(&block) if block
46
+ if modules.empty?
47
+ self
48
+ else
49
+ create_request(@parameters, @extensions | modules)
50
+ end
51
+ end
52
+
53
+ private
54
+ def add_parameter(merger_class, parameter)
55
+ merger = merger_class.new(@parameters, parameter)
56
+ create_request(merger, @extensions)
57
+ end
58
+
59
+ def create_request(parameters, extensions)
60
+ self.class.new(parameters, extensions)
61
+ end
62
+
63
+ def create_response
64
+ open_client do |client|
65
+ response = client.execute(self.class.command_name, to_parameters)
66
+ raise ErrorResponse.new(response) unless response.success?
67
+ response
68
+ end
69
+ end
70
+
71
+ def open_client
72
+ Client.open do |client|
73
+ yield(client)
74
+ end
75
+ end
76
+ end
77
+
78
+ class RequestParameter
79
+ def initialize(name, value)
80
+ @name = name
81
+ @value = value
82
+ end
83
+
84
+ def to_parameters
85
+ case @value
86
+ when Symbol
87
+ value = @value.to_s
88
+ when String
89
+ return {} if @value.empty?
90
+ value = @value
91
+ when NilClass
92
+ return {}
93
+ else
94
+ value = @value
95
+ end
96
+ {
97
+ @name => value,
98
+ }
99
+ end
100
+ end
101
+
102
+ class ValuesParameter
103
+ def initialize(names, values)
104
+ @names = names
105
+ @values = values
106
+ end
107
+
108
+ def to_parameters
109
+ case @values
110
+ when ::Array
111
+ return {} if @values.empty?
112
+ values = @values.collect(&:to_s).join(", ")
113
+ when Symbol
114
+ values = @values.to_s
115
+ when String
116
+ return {} if /\A\s*\z/ === @values
117
+ values = @values
118
+ when NilClass
119
+ return {}
120
+ else
121
+ values = @values
122
+ end
123
+ parameters = {}
124
+ @names.each do |name|
125
+ parameters[name] = values
126
+ end
127
+ parameters
128
+ end
129
+ end
130
+
131
+ class FlagsParameter
132
+ def initialize(names, flags)
133
+ @names = names
134
+ @flags = flags
135
+ end
136
+
137
+ def to_parameters
138
+ case @flags
139
+ when ::Array
140
+ return {} if @flags.empty?
141
+ flags = @flags.collect(&:to_s).join("|")
142
+ when Symbol
143
+ flags = @flags.to_s
144
+ when String
145
+ return {} if /\A\s*\z/ === @flags
146
+ flags = @flags
147
+ when NilClass
148
+ return {}
149
+ else
150
+ flags = @flags
151
+ end
152
+ parameters = {}
153
+ @names.each do |name|
154
+ parameters[name] = flags
155
+ end
156
+ parameters
157
+ end
158
+ end
159
+
160
+ class ParameterMerger
161
+ def initialize(parameters1, parameters2)
162
+ @parameters1 = parameters1
163
+ @parameters2 = parameters2
164
+ end
165
+ end
166
+
167
+ class OverwriteMerger < ParameterMerger
168
+ def to_parameters
169
+ @parameters1.to_parameters.merge(@parameters2.to_parameters)
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,39 @@
1
+ # Copyright (C) 2016 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/client/error"
18
+
19
+ module Groonga
20
+ class Client
21
+ module Request
22
+ class Error < Client::Error
23
+ end
24
+
25
+ class ErrorResponse < Error
26
+ attr_reader :response
27
+ def initialize(response)
28
+ @response = response
29
+ command = @response.command
30
+ status_code = @response.status_code
31
+ error_message = @response.error_message
32
+ message = "failed to execute: #{command.name}: #{status_code}: "
33
+ message << "<#{error_message}>"
34
+ super(message)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,292 @@
1
+ # Copyright (C) 2016 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 Request
20
+ class Select < Base
21
+ include Enumerable
22
+
23
+ class << self
24
+ def command_name
25
+ "select"
26
+ end
27
+ end
28
+
29
+ def initialize(table_or_parameters, extensions=[])
30
+ if table_or_parameters.respond_to?(:to_parameters)
31
+ parameters = table_or_parameters
32
+ else
33
+ table_name = table_or_parameters
34
+ parameters = RequestParameter.new(:table, table_name)
35
+ end
36
+ super(parameters, extensions)
37
+ end
38
+
39
+ def match_columns(value)
40
+ add_parameter(OverwriteMerger,
41
+ ValuesParameter.new([:match_columns], value))
42
+ end
43
+
44
+ def query(value)
45
+ add_parameter(QueryMerger,
46
+ RequestParameter.new(:query, value))
47
+ end
48
+
49
+ def filter(expression, values=nil)
50
+ add_parameter(FilterMerger,
51
+ FilterParameter.new(expression, values))
52
+ end
53
+
54
+ def output_columns(value)
55
+ add_parameter(OverwriteMerger,
56
+ OutputColumnsParameter.new("", value))
57
+ end
58
+
59
+ def sort_keys(value)
60
+ add_parameter(OverwriteMerger,
61
+ SortKeysParameter.new("", value))
62
+ end
63
+ alias_method :sortby, :sort_keys
64
+ alias_method :sort, :sort_keys
65
+
66
+ def offset(value)
67
+ parameter(:offset, value)
68
+ end
69
+
70
+ def limit(value)
71
+ parameter(:limit, value)
72
+ end
73
+
74
+ def paginate(page, per_page: 10)
75
+ page ||= 1
76
+ page = page.to_i
77
+ if page <= 0
78
+ offset = 0
79
+ else
80
+ offset = per_page * (page - 1)
81
+ end
82
+ offset(offset).limit(per_page)
83
+ end
84
+
85
+ def drilldowns(label)
86
+ LabeledDrilldown.new(self, label)
87
+ end
88
+
89
+ def each(&block)
90
+ response.records.each(&block)
91
+ end
92
+
93
+ private
94
+ def create_response
95
+ response = super
96
+ if paginated? and defined?(Kaminari)
97
+ response.extend(Kaminari::ConfigurationMethods::ClassMethods)
98
+ response.extend(Kaminari::PageScopeMethods)
99
+ end
100
+ response
101
+ end
102
+
103
+ def paginated?
104
+ parameters = to_parameters
105
+ parameters.key?(:offset) and parameters.key?(:limit)
106
+ end
107
+
108
+ class LabeledDrilldown
109
+ def initialize(request, label)
110
+ @request = request
111
+ @label = label
112
+ end
113
+
114
+ def keys(value)
115
+ add_parameter(OverwriteMerger,
116
+ ValuesParameter.new([:"#{prefix}keys"], value))
117
+ end
118
+
119
+ def sort_keys(value)
120
+ add_parameter(OverwriteMerger,
121
+ SortKeysParameter.new(prefix, value))
122
+ end
123
+ alias_method :sortby, :sort_keys
124
+ alias_method :sort, :sort_keys
125
+
126
+ def output_columns(value)
127
+ add_parameter(OverwriteMerger,
128
+ OutputColumnsParameter.new(prefix, value))
129
+ end
130
+
131
+ def offset(value)
132
+ @request.parameter(:"#{prefix}offset", value)
133
+ end
134
+
135
+ def limit(value)
136
+ @request.parameter(:"#{prefix}limit", value)
137
+ end
138
+
139
+ def calc_types(value)
140
+ add_parameter(OverwriteMerger,
141
+ FlagsParameter.new([:"#{prefix}calc_types"], value))
142
+ end
143
+
144
+ def calc_target(value)
145
+ @request.parameter(:"#{prefix}calc_target", value)
146
+ end
147
+
148
+ private
149
+ def prefix
150
+ "drilldowns[#{@label}]."
151
+ end
152
+
153
+ def add_parameter(merger, parameter)
154
+ @request.__send__(:add_parameter, merger, parameter)
155
+ end
156
+ end
157
+
158
+ # @private
159
+ class QueryMerger < ParameterMerger
160
+ def to_parameters
161
+ params1 = @parameters1.to_parameters
162
+ params2 = @parameters2.to_parameters
163
+ params = params1.merge(params2)
164
+ query1 = params1[:query]
165
+ query2 = params2[:query]
166
+ if query1.present? and query2.present?
167
+ params[:query] = "(#{query1}) (#{query2})"
168
+ else
169
+ params[:query] = (query1 || query2)
170
+ end
171
+ params
172
+ end
173
+ end
174
+
175
+ # @private
176
+ class FilterMerger < ParameterMerger
177
+ def to_parameters
178
+ params1 = @parameters1.to_parameters
179
+ params2 = @parameters2.to_parameters
180
+ params = params1.merge(params2)
181
+ filter1 = params1[:filter]
182
+ filter2 = params2[:filter]
183
+ if filter1.present? and filter2.present?
184
+ params[:filter] = "(#{filter1}) && (#{filter2})"
185
+ else
186
+ params[:filter] = (filter1 || filter2)
187
+ end
188
+ params
189
+ end
190
+ end
191
+
192
+ # @private
193
+ class FilterParameter
194
+ def initialize(expression, values)
195
+ @expression = expression
196
+ @values = values
197
+ end
198
+
199
+ def to_parameters
200
+ case @expression
201
+ when String
202
+ return {} if /\A\s*\z/ === @expression
203
+ expression = @expression
204
+ when NilClass
205
+ return {}
206
+ else
207
+ expression = @expression
208
+ end
209
+
210
+ if @values.is_a?(::Hash) and not @values.empty?
211
+ escaped_values = {}
212
+ @values.each do |key, value|
213
+ escaped_values[key] = escape_filter_value(value)
214
+ end
215
+ expression = expression % escaped_values
216
+ end
217
+
218
+ {
219
+ filter: expression,
220
+ }
221
+ end
222
+
223
+ private
224
+ def escape_filter_value(value)
225
+ case value
226
+ when Numeric
227
+ value
228
+ when TrueClass, FalseClass
229
+ value
230
+ when NilClass
231
+ "null"
232
+ when String
233
+ ScriptSyntax.format_string(value)
234
+ when Symbol
235
+ ScriptSyntax.format_string(value.to_s)
236
+ when ::Array
237
+ escaped_value = "["
238
+ value.each_with_index do |element, i|
239
+ escaped_value << ", " if i > 0
240
+ escaped_value << escape_filter_value(element)
241
+ end
242
+ escaped_value << "]"
243
+ escaped_value
244
+ when ::Hash
245
+ escaped_value = "{"
246
+ value.each_with_index do |(k, v), i|
247
+ escaped_value << ", " if i > 0
248
+ escaped_value << escape_filter_value(k.to_s)
249
+ escaped_value << ": "
250
+ escaped_value << escape_filter_value(v)
251
+ end
252
+ escaped_value << "}"
253
+ escaped_value
254
+ else
255
+ value
256
+ end
257
+ end
258
+ end
259
+
260
+ # @private
261
+ class OutputColumnsParameter < ValuesParameter
262
+ def initialize(prefix, output_columns)
263
+ super([:"#{prefix}output_columns"], output_columns)
264
+ end
265
+
266
+ def to_parameters
267
+ parameters = super
268
+ @names.each do |name|
269
+ output_columns = parameters[name]
270
+ if output_columns and output_columns.include?("(")
271
+ parameters[:command_version] = "2"
272
+ break
273
+ end
274
+ end
275
+ parameters
276
+ end
277
+ end
278
+
279
+ # @private
280
+ class SortKeysParameter < ValuesParameter
281
+ def initialize(prefix, output_columns)
282
+ names = [
283
+ :"#{prefix}sort_keys",
284
+ :"#{prefix}sortby", # for backward compatibility
285
+ ]
286
+ super(names, output_columns)
287
+ end
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end