groonga-client 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
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