gcloud 0.5.0 → 0.6.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.
Files changed (52) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +8 -0
  3. data/lib/gcloud.rb +48 -30
  4. data/lib/gcloud/bigquery.rb +4 -6
  5. data/lib/gcloud/bigquery/connection.rb +2 -14
  6. data/lib/gcloud/bigquery/dataset.rb +41 -42
  7. data/lib/gcloud/bigquery/project.rb +50 -46
  8. data/lib/gcloud/bigquery/query_job.rb +7 -8
  9. data/lib/gcloud/bigquery/table.rb +54 -55
  10. data/lib/gcloud/bigquery/table/schema.rb +30 -40
  11. data/lib/gcloud/bigquery/view.rb +10 -11
  12. data/lib/gcloud/credentials.rb +19 -25
  13. data/lib/gcloud/datastore.rb +4 -6
  14. data/lib/gcloud/datastore/dataset.rb +3 -5
  15. data/lib/gcloud/dns.rb +4 -6
  16. data/lib/gcloud/dns/connection.rb +17 -16
  17. data/lib/gcloud/dns/importer.rb +5 -11
  18. data/lib/gcloud/dns/project.rb +11 -12
  19. data/lib/gcloud/dns/zone.rb +52 -92
  20. data/lib/gcloud/dns/zone/transaction.rb +2 -2
  21. data/lib/gcloud/pubsub.rb +4 -6
  22. data/lib/gcloud/pubsub/connection.rb +1 -12
  23. data/lib/gcloud/pubsub/project.rb +30 -36
  24. data/lib/gcloud/pubsub/subscription.rb +18 -26
  25. data/lib/gcloud/pubsub/topic.rb +16 -26
  26. data/lib/gcloud/resource_manager.rb +5 -6
  27. data/lib/gcloud/resource_manager/connection.rb +4 -4
  28. data/lib/gcloud/resource_manager/manager.rb +10 -14
  29. data/lib/gcloud/resource_manager/project.rb +3 -5
  30. data/lib/gcloud/search.rb +295 -0
  31. data/lib/gcloud/search/api_client.rb +144 -0
  32. data/lib/gcloud/search/connection.rb +146 -0
  33. data/lib/gcloud/search/credentials.rb +30 -0
  34. data/lib/gcloud/search/document.rb +301 -0
  35. data/lib/gcloud/search/document/list.rb +85 -0
  36. data/lib/gcloud/search/errors.rb +67 -0
  37. data/lib/gcloud/search/field_value.rb +164 -0
  38. data/lib/gcloud/search/field_values.rb +263 -0
  39. data/lib/gcloud/search/fields.rb +267 -0
  40. data/lib/gcloud/search/index.rb +613 -0
  41. data/lib/gcloud/search/index/list.rb +90 -0
  42. data/lib/gcloud/search/project.rb +197 -0
  43. data/lib/gcloud/search/result.rb +169 -0
  44. data/lib/gcloud/search/result/list.rb +95 -0
  45. data/lib/gcloud/storage.rb +4 -6
  46. data/lib/gcloud/storage/bucket.rb +55 -43
  47. data/lib/gcloud/storage/bucket/cors.rb +5 -7
  48. data/lib/gcloud/storage/file.rb +35 -30
  49. data/lib/gcloud/storage/file/acl.rb +12 -16
  50. data/lib/gcloud/storage/project.rb +56 -22
  51. data/lib/gcloud/version.rb +1 -1
  52. metadata +20 -3
@@ -0,0 +1,267 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "gcloud/search/field_values"
17
+ require "gcloud/search/field_value"
18
+
19
+ module Gcloud
20
+ module Search
21
+ ##
22
+ # = Fields
23
+ #
24
+ # Fields is the object that provides access to a document's fields.
25
+ #
26
+ # Each field has a name (String) and a list of values. Each field name
27
+ # consists of only ASCII characters, must be unique within the document and
28
+ # is case sensitive. A field name must start with a letter and can contain
29
+ # letters, digits, or underscore, with a maximum of 500 characters.
30
+ #
31
+ # A field can have multiple values with same or different types; however, it
32
+ # cannot have multiple datetime (DateTime) or number (Float) values. (See
33
+ # FieldValues and FieldValue)
34
+ #
35
+ # require "gcloud"
36
+ #
37
+ # gcloud = Gcloud.new
38
+ # search = gcloud.search
39
+ # index = search.index "products"
40
+ #
41
+ # document = index.document "product-sku-000001"
42
+ # puts "The document #{document.doc_id} has the following fields:"
43
+ # document.names.each do |name|
44
+ # puts "* #{name}:"
45
+ # document[name].each do |value|
46
+ # puts " * #{value} (#{value.type})"
47
+ # end
48
+ # end
49
+ #
50
+ # For more information see {Documents and
51
+ # fields}[https://cloud.google.com/search/documents_indexes].
52
+ #
53
+ class Fields
54
+ include Enumerable
55
+
56
+ ##
57
+ # Create a new empty fields object.
58
+ def initialize #:nodoc:
59
+ @hash = {}
60
+ end
61
+
62
+ ##
63
+ # Retrieve the field values associated to a field name.
64
+ #
65
+ # === Parameters
66
+ #
67
+ # +name+::
68
+ # The name of the field. New values will be configured with this name.
69
+ # (+String+)
70
+ #
71
+ # === Returns
72
+ #
73
+ # FieldValues
74
+ #
75
+ # === Example
76
+ #
77
+ # require "gcloud"
78
+ #
79
+ # gcloud = Gcloud.new
80
+ # search = gcloud.search
81
+ # index = search.index "products"
82
+ #
83
+ # document = index.document "product-sku-000001"
84
+ # puts "The document description is:"
85
+ # document.fields["description"].each do |value|
86
+ # puts "* #{value} (#{value.type}) [#{value.lang}]"
87
+ # end
88
+ #
89
+ def [] name
90
+ @hash[name] ||= FieldValues.new name
91
+ end
92
+
93
+ # rubocop:disable Metrics/LineLength
94
+ # Disabled because there are links in the docs that are long.
95
+
96
+ ##
97
+ # Add a new value. If the field name does not exist it will be added. If
98
+ # the field value is a DateTime or Numeric, or the type is set to
99
+ # +:datetime+ or +:number+, then the added value will replace any existing
100
+ # values of the same type (since there can be only one).
101
+ #
102
+ # === Parameters
103
+ #
104
+ # +name+::
105
+ # The name of the field. (+String+)
106
+ # +value+::
107
+ # The value to add to the field. (+String+ or +Datetime+ or +Float+)
108
+ # +type+::
109
+ # The type of the field value. An attempt is made to set the correct
110
+ # type when this option is missing, although it must be provided for
111
+ # +:geo+ values. A field can have multiple values with same or different
112
+ # types; however, it cannot have multiple +:datetime+ or +:number+
113
+ # values. (+Symbol+)
114
+ #
115
+ # The following values are supported:
116
+ # * +:default+ - The value is a string. The format will be automatically
117
+ # detected. This is the default value for strings.
118
+ # * +:text+ - The value is a string with maximum length 1024**2
119
+ # characters.
120
+ # * +:html+ - The value is an HTML-formatted string with maximum length
121
+ # 1024**2 characters.
122
+ # * +:atom+ - The value is a string with maximum length 500 characters.
123
+ # * +:geo+ - The value is a point on earth described by latitude and
124
+ # longitude coordinates, represented in string with any of the listed
125
+ # {ways of writing
126
+ # coordinates}[http://en.wikipedia.org/wiki/Geographic_coordinate_conversion].
127
+ # * +:datetime+ - The value is a +DateTime+.
128
+ # * +:number+ - The value is a +Numeric+ between -2,147,483,647 and
129
+ # 2,147,483,647. The value will be stored as a double precision
130
+ # floating point value in Cloud Search.
131
+ # +lang+::
132
+ # The language of a string value. Must be a valid {ISO 639-1
133
+ # code}[https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes].
134
+ # (+String+)
135
+ #
136
+ # === Example
137
+ #
138
+ # require "gcloud"
139
+ #
140
+ # gcloud = Gcloud.new
141
+ # search = gcloud.search
142
+ # index = search.index "products"
143
+ #
144
+ # document = index.document "product-sku-000001"
145
+ # document.fields.add "sku", "product-sku-000001", type: :atom
146
+ # document.fields.add "description", "The best T-shirt ever.",
147
+ # type: :text, lang: "en"
148
+ # document.fields.add "description", "<p>The best T-shirt ever.</p>",
149
+ # type: :html, lang: "en"
150
+ # document.fields.add "price", 24.95
151
+ #
152
+ def add name, value, type: nil, lang: nil
153
+ @hash[name] ||= FieldValues.new name
154
+ @hash[name].add value, type: type, lang: lang
155
+ end
156
+
157
+ # rubocop:enable Metrics/LineLength
158
+
159
+ ##
160
+ # Deletes a field and all values.
161
+ #
162
+ # === Parameters
163
+ #
164
+ # +name+::
165
+ # The name of the field. (+String+)
166
+ #
167
+ # === Example
168
+ #
169
+ # require "gcloud"
170
+ #
171
+ # gcloud = Gcloud.new
172
+ # search = gcloud.search
173
+ # index = search.index "products"
174
+ #
175
+ # document = index.document "product-sku-000001"
176
+ # document.fields.delete "description"
177
+ #
178
+ def delete name, &block
179
+ @hash.delete name, &block
180
+ end
181
+
182
+ ##
183
+ # Calls block once for each field, passing the field name and values pair
184
+ # as parameters. If no block is given an enumerator is returned instead.
185
+ #
186
+ # === Example
187
+ #
188
+ # require "gcloud"
189
+ #
190
+ # gcloud = Gcloud.new
191
+ # search = gcloud.search
192
+ # index = search.index "products"
193
+ #
194
+ # document = index.document "product-sku-000001"
195
+ # puts "The document #{document.doc_id} has the following fields:"
196
+ # document.fields.each do |name, values|
197
+ # puts "* #{name}:"
198
+ # values.each do |value|
199
+ # puts " * #{value} (#{value.type})"
200
+ # end
201
+ # end
202
+ #
203
+ def each &block
204
+ # Only yield fields that have values.
205
+ fields_with_values.each(&block)
206
+ end
207
+
208
+ ##
209
+ # Returns a new array populated with all the field names.
210
+ #
211
+ # require "gcloud"
212
+ #
213
+ # gcloud = Gcloud.new
214
+ # search = gcloud.search
215
+ # index = search.index "products"
216
+ #
217
+ # document = index.document "product-sku-000001"
218
+ # puts "The document #{document.doc_id} has the following fields:"
219
+ # document.fields.names.each do |name|
220
+ # puts "* #{name}:"
221
+ # end
222
+ #
223
+ def names
224
+ # Only return fields that have values.
225
+ fields_with_values.keys
226
+ end
227
+
228
+ ##
229
+ # Create a new Fields instance from a raw Hash.
230
+ def self.from_raw raw #:nodoc:
231
+ hsh = {}
232
+ raw.each do |k, v|
233
+ hsh[k] = FieldValues.from_raw k, v["values"]
234
+ end unless raw.nil?
235
+ fields = new
236
+ fields.instance_variable_set "@hash", hsh
237
+ fields
238
+ end
239
+
240
+ ##
241
+ # Create a raw Hash object containing all the field names and values.
242
+ def to_raw #:nodoc:
243
+ hsh = {}
244
+ @hash.each do |k, v|
245
+ hsh[k] = v.to_raw unless v.empty?
246
+ end
247
+ hsh
248
+ end
249
+
250
+ protected
251
+
252
+ ##
253
+ # Find all the fields that have values. This is needed because a field is
254
+ # required to have at least one value.
255
+ #
256
+ # Users can remove all values, and the empty FieldValues object will
257
+ # remain in the internal hash. This is the same as not having that field.
258
+ #
259
+ # Users can also reference the field by name before adding a value. So we
260
+ # have multiple valid use cases which add an empty FieldValues object to
261
+ # the hash.
262
+ def fields_with_values #:nodoc:
263
+ @hash.select { |_name, values| values.any? }
264
+ end
265
+ end
266
+ end
267
+ end
@@ -0,0 +1,613 @@
1
+ #--
2
+ # Copyright 2015 Google Inc. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require "gcloud/search/document"
17
+ require "gcloud/search/index/list"
18
+ require "gcloud/search/result"
19
+
20
+ module Gcloud
21
+ module Search
22
+ ##
23
+ # = Index
24
+ #
25
+ # An index manages Document instances for retrieval. Indexes cannot be
26
+ # created, updated, or deleted directly on the server: They are derived from
27
+ # the documents that reference them. You can manage groups of documents by
28
+ # putting them into separate indexes.
29
+ #
30
+ # With an index, you can retrieve documents with #find and #documents;
31
+ # manage them with #document, #save, and #remove; and perform searches over
32
+ # their fields with #search.
33
+ #
34
+ # require "gcloud"
35
+ #
36
+ # gcloud = Gcloud.new
37
+ # search = gcloud.search
38
+ # index = search.index "books"
39
+ #
40
+ # results = index.search "dark stormy"
41
+ # results.each do |result|
42
+ # puts result.doc_id
43
+ # end
44
+ #
45
+ # For more information, see {Documents and
46
+ # Indexes}[https://cloud.google.com/search/documents_indexes].
47
+ #
48
+ class Index
49
+ ##
50
+ # The Connection object.
51
+ attr_accessor :connection #:nodoc:
52
+
53
+ ##
54
+ # The raw data object.
55
+ attr_accessor :raw #:nodoc:
56
+
57
+ ##
58
+ # Creates a new Index instance.
59
+ #
60
+ def initialize #:nodoc:
61
+ @connection = nil
62
+ @raw = nil
63
+ end
64
+
65
+ ##
66
+ # The index identifier. May be defined by the server or by the client.
67
+ # Must be unique within the project. It cannot be an empty string. It must
68
+ # contain only visible, printable ASCII characters (ASCII codes 33 through
69
+ # 126 inclusive) and be no longer than 100 characters. It cannot begin
70
+ # with an exclamation point (<code>!</code>), and it cannot begin and end
71
+ # with double underscores (<code>__</code>).
72
+ def index_id
73
+ @raw["indexId"]
74
+ end
75
+
76
+ ##
77
+ # The names of fields in which TEXT values are stored. See {Index schemas
78
+ # }[https://cloud.google.com/search/documents_indexes#index_schemas].
79
+ def text_fields
80
+ return @raw["indexedField"]["textFields"] if @raw["indexedField"]
81
+ []
82
+ end
83
+
84
+ ##
85
+ # The names of fields in which HTML values are stored. See {Index schemas
86
+ # }[https://cloud.google.com/search/documents_indexes#index_schemas].
87
+ def html_fields
88
+ return @raw["indexedField"]["htmlFields"] if @raw["indexedField"]
89
+ []
90
+ end
91
+
92
+ ##
93
+ # The names of fields in which ATOM values are stored. See {Index schemas
94
+ # }[https://cloud.google.com/search/documents_indexes#index_schemas].
95
+ def atom_fields
96
+ return @raw["indexedField"]["atomFields"] if @raw["indexedField"]
97
+ []
98
+ end
99
+
100
+ ##
101
+ # The names of fields in which DATE values are stored. See {Index schemas
102
+ # }[https://cloud.google.com/search/documents_indexes#index_schemas].
103
+ def datetime_fields
104
+ return @raw["indexedField"]["dateFields"] if @raw["indexedField"]
105
+ []
106
+ end
107
+
108
+ ##
109
+ # The names of fields in which NUMBER values are stored. See {Indexschemas
110
+ # }[https://cloud.google.com/search/documents_indexes#index_schemas].
111
+ def number_fields
112
+ return @raw["indexedField"]["numberFields"] if @raw["indexedField"]
113
+ []
114
+ end
115
+
116
+ ##
117
+ # The names of fields in which GEO values are stored. See {Index
118
+ # }[https://cloud.google.com/search/documents_indexes#index_schemas].
119
+ def geo_fields
120
+ return @raw["indexedField"]["geoFields"] if @raw["indexedField"]
121
+ []
122
+ end
123
+
124
+ ##
125
+ # The names of all the fields that are stored on the index.
126
+ def field_names
127
+ (text_fields + html_fields + atom_fields + datetime_fields +
128
+ number_fields + geo_fields).uniq
129
+ end
130
+
131
+ ##
132
+ # The field value types that are stored on the field name.
133
+ def field_types_for name
134
+ {
135
+ text: text_fields.include?(name),
136
+ html: html_fields.include?(name),
137
+ atom: atom_fields.include?(name),
138
+ datetime: datetime_fields.include?(name),
139
+ number: number_fields.include?(name),
140
+ geo: geo_fields.include?(name)
141
+ }.delete_if { |_k, v| !v }.keys
142
+ end
143
+
144
+ ##
145
+ # Retrieves an existing document by id.
146
+ #
147
+ # === Parameters
148
+ #
149
+ # +doc_id+::
150
+ # The id of a document or a Document instance. (+String+ or Document)
151
+ #
152
+ # === Returns
153
+ #
154
+ # Gcloud::Search::Document or +nil+ if the document does not exist
155
+ #
156
+ # === Example
157
+ #
158
+ # require "gcloud"
159
+ #
160
+ # gcloud = Gcloud.new
161
+ # search = gcloud.search
162
+ # index = search.index "products"
163
+ #
164
+ # document = index.find "product-sku-000001"
165
+ # puts document.doc_id
166
+ #
167
+ def find doc_id
168
+ # Get the id if passes a Document object
169
+ doc_id = doc_id.doc_id if doc_id.respond_to? :doc_id
170
+ ensure_connection!
171
+ resp = connection.get_doc index_id, doc_id
172
+ return Document.from_hash(JSON.parse(resp.body)) if resp.success?
173
+ return nil if resp.status == 404
174
+ fail ApiError.from_response(resp)
175
+ rescue JSON::ParserError
176
+ raise ApiError.from_response(resp)
177
+ end
178
+ alias_method :get, :find
179
+
180
+ ##
181
+ # Helper for creating a new Document instance. The returned instance is
182
+ # local: It is either not yet saved to the service (see #save), or if it
183
+ # has been given the id of an existing document, it is not yet populated
184
+ # with the document's data (see #find).
185
+ #
186
+ # === Parameters
187
+ #
188
+ # +doc_id+::
189
+ # The unique identifier of the new document. This is optional. When the
190
+ # document is saved, this value must contain only visible, printable
191
+ # ASCII characters (ASCII codes 33 through 126 inclusive) and be no
192
+ # longer than 500 characters. It cannot begin with an exclamation point
193
+ # (<code>!</code>), and it cannot begin and end with double underscores
194
+ # (<code>__</code>). (+String+)
195
+ # +rank+::
196
+ # The rank of the new document. This is optional. A positive integer
197
+ # which determines the default ordering of documents returned from a
198
+ # search. It is a bad idea to assign the same rank to many documents,
199
+ # and the same rank should never be assigned to more than 10,000
200
+ # documents. By default (when it is not specified or set to 0), it is
201
+ # set at the time the document is saved to the number of seconds since
202
+ # January 1, 2011. The rank can be used in the +expressions+, +order+,
203
+ # and +fields+ options in #search, where it should referenced as
204
+ # +rank+. (+Integer+)
205
+ #
206
+ # === Returns
207
+ #
208
+ # Gcloud::Search::Document
209
+ #
210
+ # === Example
211
+ #
212
+ # require "gcloud"
213
+ #
214
+ # gcloud = Gcloud.new
215
+ # search = gcloud.search
216
+ # index = search.index "products"
217
+ #
218
+ # document = index.document "product-sku-000001"
219
+ # document.doc_id #=> nil
220
+ # document.rank #=> nil
221
+ #
222
+ # To check if an index already contains a document with the same id, pass
223
+ # the instance to #find:
224
+ #
225
+ # require "gcloud"
226
+ #
227
+ # gcloud = Gcloud.new
228
+ # search = gcloud.search
229
+ # index = search.index "products"
230
+ #
231
+ # document = index.document "product-sku-000001"
232
+ # document = index.find document # returns nil if not present
233
+ #
234
+ def document doc_id = nil, rank = nil
235
+ Document.new.tap do |d|
236
+ d.doc_id = doc_id
237
+ d.rank = rank
238
+ end
239
+ end
240
+
241
+ ##
242
+ # Retrieves the list of documents belonging to the index.
243
+ #
244
+ # === Parameters
245
+ #
246
+ # +token+::
247
+ # A previously-returned page token representing part of the larger set
248
+ # of results to view. (+String+)
249
+ # +max+::
250
+ # Maximum number of documents to return. The default is +100+.
251
+ # (+Integer+)
252
+ #
253
+ # === Returns
254
+ #
255
+ # Array of Gcloud::Search::Document (See Gcloud::Search::Document::List)
256
+ #
257
+ # === Examples
258
+ #
259
+ # require "gcloud"
260
+ #
261
+ # gcloud = Gcloud.new
262
+ # search = gcloud.search
263
+ # index = search.index "products"
264
+ #
265
+ # documents = index.documents
266
+ # documents.each do |index|
267
+ # puts index.index_id
268
+ # end
269
+ #
270
+ # If you have a significant number of documents, you may need to paginate
271
+ # through them: (See Gcloud::Search::Document::List)
272
+ #
273
+ # require "gcloud"
274
+ #
275
+ # gcloud = Gcloud.new
276
+ # search = gcloud.search
277
+ # index = search.index "products"
278
+ #
279
+ # documents = index.documents
280
+ # loop do
281
+ # documents.each do |index|
282
+ # puts index.index_id
283
+ # end
284
+ # break unless documents.next?
285
+ # documents = documents.next
286
+ # end
287
+ #
288
+ def documents token: nil, max: nil, view: nil
289
+ ensure_connection!
290
+ options = { token: token, max: max, view: view }
291
+ resp = connection.list_docs index_id, options
292
+ return Document::List.from_response(resp, self) if resp.success?
293
+ fail ApiError.from_response(resp)
294
+ end
295
+
296
+ ##
297
+ # Saves a new or existing document to the index. If the document instance
298
+ # is new and has been given an id (see #document), it will replace an
299
+ # existing document in the index that has the same unique id.
300
+ #
301
+ # === Parameters
302
+ #
303
+ # +document+::
304
+ # A Document instance, either new (see #document) or existing (see
305
+ # #find).
306
+ #
307
+ # === Returns
308
+ #
309
+ # Gcloud::Search::Document
310
+ #
311
+ # === Example
312
+ #
313
+ # require "gcloud"
314
+ #
315
+ # gcloud = Gcloud.new
316
+ # search = gcloud.search
317
+ # index = search.index "products"
318
+ #
319
+ # document = index.document "product-sku-000001"
320
+ # document.doc_id #=> nil
321
+ # document.rank #=> nil
322
+ #
323
+ # document = index.save document
324
+ # document.doc_id #=> "-2486020449015432113"
325
+ # document.rank #=> 154223228
326
+ #
327
+ def save document
328
+ ensure_connection!
329
+ resp = connection.create_doc index_id, document.to_hash
330
+ if resp.success?
331
+ raw = document.instance_variable_get "@raw"
332
+ raw.merge! JSON.parse(resp.body)
333
+ return document
334
+ end
335
+ fail ApiError.from_response(resp)
336
+ rescue JSON::ParserError
337
+ raise ApiError.from_response(resp)
338
+ end
339
+
340
+ ##
341
+ # Permanently deletes the document from the index.
342
+ #
343
+ # === Parameters
344
+ #
345
+ # +doc_id+::
346
+ # The id of the document. (+String+)
347
+ #
348
+ # === Returns
349
+ #
350
+ # +true+ if successful
351
+ #
352
+ # === Example
353
+ #
354
+ # require "gcloud"
355
+ #
356
+ # gcloud = Gcloud.new
357
+ # search = gcloud.search
358
+ # index = search.index "products"
359
+ #
360
+ # index.remove "product-sku-000001"
361
+ #
362
+ def remove doc_id
363
+ # Get the id if passes a Document object
364
+ doc_id = doc_id.doc_id if doc_id.respond_to? :doc_id
365
+ ensure_connection!
366
+ resp = connection.delete_doc index_id, doc_id
367
+ return true if resp.success?
368
+ fail ApiError.from_response(resp)
369
+ end
370
+
371
+ ##
372
+ # Permanently deletes the index by deleting its documents. (Indexes cannot
373
+ # be created, updated, or deleted directly on the server: They are derived
374
+ # from the documents that reference them.)
375
+ #
376
+ # === Parameters
377
+ #
378
+ # +force+::
379
+ # If +true+, ensures the deletion of the index by first deleting all
380
+ # documents. If +false+ and the index contains documents, the request
381
+ # will fail. Default is +false+. (+Boolean+)
382
+ #
383
+ # === Examples
384
+ #
385
+ # require "gcloud"
386
+ #
387
+ # gcloud = Gcloud.new
388
+ # search = gcloud.search
389
+ # index = search.index "books"
390
+ #
391
+ # An index containing documents can be forcefully deleted with the +force+
392
+ # option:
393
+ #
394
+ # require "gcloud"
395
+ #
396
+ # gcloud = Gcloud.new
397
+ # search = gcloud.search
398
+ # index = search.index "books"
399
+ # index.delete force: true
400
+ #
401
+ def delete force: false
402
+ ensure_connection!
403
+ docs_to_be_removed = documents view: "ID_ONLY"
404
+ return if docs_to_be_removed.empty?
405
+ unless force
406
+ fail "Unable to delete because documents exist. Use force option."
407
+ end
408
+ while docs_to_be_removed
409
+ docs_to_be_removed.each { |d| remove d }
410
+ if docs_to_be_removed.next?
411
+ docs_to_be_removed = documents token: docs_to_be_removed.token,
412
+ view: "ID_ONLY"
413
+ else
414
+ docs_to_be_removed = nil
415
+ end
416
+ end
417
+ end
418
+
419
+ ##
420
+ # New Index from a raw data object.
421
+ def self.from_raw raw, conn #:nodoc:
422
+ new.tap do |f|
423
+ f.raw = raw
424
+ f.connection = conn
425
+ end
426
+ end
427
+
428
+ # rubocop:disable Metrics/LineLength
429
+ # Disabled because there are links in the docs that are long.
430
+
431
+ ##
432
+ # Runs a search against the documents in the index using the provided
433
+ # query. For more information see the REST API documentation for
434
+ # {indexes.search}[https://cloud.google.com/search/reference/rest/v1/projects/indexes/search].
435
+ #
436
+ # === Parameters
437
+ #
438
+ # +query+::
439
+ # The query string in search query syntax. If the query is +nil+ or
440
+ # empty, all documents are returned. For more information see {Query
441
+ # Strings}[https://cloud.google.com/search/query]. (+String+)
442
+ # +expressions+::
443
+ # Customized expressions used in +order+ or +fields+. The expression can
444
+ # contain fields in Document, the built-in fields ( +rank+, the document
445
+ # +rank+, and +score+ if scoring is enabled) and fields defined in
446
+ # +expressions+. All field expressions expressed as a +Hash+ with the
447
+ # keys as the +name+ and the values as the +expression+. The expression
448
+ # value can be a combination of supported functions encoded in the
449
+ # string. Expressions involving number fields can use the arithmetical
450
+ # operators (+, -, *, /) and the built-in numeric functions (+max+,
451
+ # +min+, +pow+, +count+, +log+, +abs+). Expressions involving geopoint
452
+ # fields can use the +geopoint+ and +distance+ functions. Expressions
453
+ # for text and html fields can use the +snippet+ function. (+Hash+)
454
+ # +matched_count_accuracy+::
455
+ # Minimum accuracy requirement for Result::List#matched_count. If
456
+ # specified, +matched_count+ will be accurate to at least that number.
457
+ # For example, when set to 100, any <code>matched_count <= 100</code> is
458
+ # accurate. This option may add considerable latency/expense. By default
459
+ # (when it is not specified or set to 0), the accuracy is the same as
460
+ # +max+. (+Integer+)
461
+ # +offset+::
462
+ # Used to advance pagination to an arbitrary result, independent of the
463
+ # previous results. Offsets are an inefficient alternative to using
464
+ # +token+. (Both cannot be both set.) The default is 0.
465
+ # (+Integer+)
466
+ # +order+::
467
+ # A comma-separated list of fields for sorting on the search result,
468
+ # including fields from Document, the built-in fields (+rank+ and
469
+ # +score+), and fields defined in expressions. The default sorting
470
+ # order is ascending. To specify descending order for a field, a suffix
471
+ # <code>" desc"</code> should be appended to the field name. For
472
+ # example: <code>orderBy="foo desc,bar"</code>. The default value for
473
+ # text sort is the empty string, and the default value for numeric sort
474
+ # is 0. If not specified, the search results are automatically sorted by
475
+ # descending +rank+. Sorting by ascending +rank+ is not allowed.
476
+ # (+String+)
477
+ # +fields+::
478
+ # The fields to return in the Search::Result objects. These can be
479
+ # fields from Document, the built-in fields +rank+ and +score+, and
480
+ # fields defined in expressions. The default is to return all fields.
481
+ # (+String+ or +Array+ of +String+)
482
+ # +scorer+::
483
+ # The scoring function to invoke on a search result for this query. If
484
+ # scorer is not set, scoring is disabled and +score+ is 0 for all
485
+ # documents in the search result. To enable document relevancy score
486
+ # based on term frequency, set +scorer+ to +:generic+.
487
+ # (+String+ or +Symbol+)
488
+ # +scorer_size+::
489
+ # Maximum number of top retrieved results to score. It is valid only
490
+ # when +scorer+ is set. The default is 100. (+Integer+)
491
+ # +token+::
492
+ # A previously-returned page token representing part of the larger set
493
+ # of results to view. (+String+)
494
+ # +max+::
495
+ # Maximum number of results to return per page. (+Integer+)
496
+ #
497
+ # === Returns
498
+ #
499
+ # Array of Gcloud::Search::Result (See Gcloud::Search::Result::List)
500
+ #
501
+ # === Examples
502
+ #
503
+ # require "gcloud"
504
+ #
505
+ # gcloud = Gcloud.new
506
+ # search = gcloud.search
507
+ # index = search.index "books"
508
+ #
509
+ # results = index.search "dark stormy"
510
+ # results.each do |result|
511
+ # puts result.doc_id
512
+ # end
513
+ #
514
+ # If you have a significant number of search results, you may need to
515
+ # paginate through them: (See Gcloud::Search::Result::List)
516
+ #
517
+ # require "gcloud"
518
+ #
519
+ # gcloud = Gcloud.new
520
+ # search = gcloud.search
521
+ # index = search.index "books"
522
+ #
523
+ # results = index.results
524
+ # loop do
525
+ # results.each do |result|
526
+ # puts result.doc_id
527
+ # end
528
+ # break unless results.next?
529
+ # results = results.next
530
+ # end
531
+ #
532
+ # By default, Result objects are sorted by document rank. For more information
533
+ # see the {REST API documentation for Document.rank}[https://cloud.google.com/search/reference/rest/v1/projects/indexes/documents#resource_representation.google.cloudsearch.v1.Document.rank].
534
+ #
535
+ # You can specify how to sort results with the +order+ option. In the example
536
+ # below, the <code>-</code> character before +avg_review+ means that results
537
+ # will be sorted in ascending order by +published+ and then in descending
538
+ # order by +avg_review+.
539
+ #
540
+ # require "gcloud"
541
+ #
542
+ # gcloud = Gcloud.new
543
+ # search = gcloud.search
544
+ # index = search.index "books"
545
+ #
546
+ # results = index.search "dark stormy", order: "published, avg_review desc"
547
+ # documents = index.search query # API call
548
+ #
549
+ # You can add computed fields with the +expressions+ option, and limit the
550
+ # fields that are returned with the +fields+ option:
551
+ #
552
+ # require "gcloud"
553
+ #
554
+ # gcloud = Gcloud.new
555
+ # search = gcloud.search
556
+ # index = search.index "products"
557
+ #
558
+ # results = index.search "cotton T-shirt",
559
+ # expressions: { total_price: "(price + tax)" },
560
+ # fields: ["name", "total_price", "highlight"]
561
+ #
562
+ # Just as in documents, Result data is accessible via Fields methods:
563
+ #
564
+ # require "gcloud"
565
+ #
566
+ # gcloud = Gcloud.new
567
+ # search = gcloud.search
568
+ # index = search.index "products"
569
+ # document = index.find "product-sku-000001"
570
+ # results = index.search "cotton T-shirt"
571
+ # values = results[0]["description"]
572
+ #
573
+ # values[0] #=> "100% organic cotton ruby gem T-shirt"
574
+ # values[0].type #=> :text
575
+ # values[0].lang #=> "en"
576
+ # values[1] #=> "<p>100% organic cotton ruby gem T-shirt</p>"
577
+ # values[1].type #=> :html
578
+ # values[1].lang #=> "en"
579
+ #
580
+ def search query, expressions: nil, matched_count_accuracy: nil,
581
+ offset: nil, order: nil, fields: nil, scorer: nil,
582
+ scorer_size: nil, token: nil, max: nil
583
+ ensure_connection!
584
+ options = { expressions: format_expressions(expressions),
585
+ matched_count_accuracy: matched_count_accuracy,
586
+ offset: offset, order: order, fields: fields,
587
+ scorer: scorer, scorer_size: scorer_size, token: token,
588
+ max: max }
589
+ resp = connection.search index_id, query, options
590
+ if resp.success?
591
+ Result::List.from_response resp, self, query, options
592
+ else
593
+ fail ApiError.from_response(resp)
594
+ end
595
+ end
596
+
597
+ # rubocop:enable Metrics/LineLength
598
+
599
+ protected
600
+
601
+ ##
602
+ # Raise an error unless an active connection is available.
603
+ def ensure_connection!
604
+ fail "Must have active connection" unless connection
605
+ end
606
+
607
+ def format_expressions expressions
608
+ return nil if expressions.nil?
609
+ expressions.to_h.map { |k, v| { name: k, expression: v } }
610
+ end
611
+ end
612
+ end
613
+ end