google-cloud-firestore 2.11.0 → 2.13.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/google/cloud/firestore/bulk_commit_batch.rb +73 -0
- data/lib/google/cloud/firestore/bulk_writer.rb +558 -0
- data/lib/google/cloud/firestore/bulk_writer_exception.rb +40 -0
- data/lib/google/cloud/firestore/bulk_writer_operation.rb +126 -0
- data/lib/google/cloud/firestore/bulk_writer_scheduler.rb +164 -0
- data/lib/google/cloud/firestore/client.rb +81 -0
- data/lib/google/cloud/firestore/errors.rb +60 -0
- data/lib/google/cloud/firestore/filter.rb +326 -0
- data/lib/google/cloud/firestore/promise/future.rb +97 -0
- data/lib/google/cloud/firestore/query.rb +68 -86
- data/lib/google/cloud/firestore/rate_limiter.rb +80 -0
- data/lib/google/cloud/firestore/service.rb +12 -0
- data/lib/google/cloud/firestore/version.rb +1 -1
- metadata +11 -2
@@ -0,0 +1,326 @@
|
|
1
|
+
# Copyright 2023 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
|
16
|
+
require "google/cloud/firestore/v1"
|
17
|
+
|
18
|
+
module Google
|
19
|
+
module Cloud
|
20
|
+
module Firestore
|
21
|
+
##
|
22
|
+
# Represents the filter for structured query.
|
23
|
+
#
|
24
|
+
class Filter
|
25
|
+
##
|
26
|
+
# @private Object of type
|
27
|
+
# Google::Cloud::Firestore::V1::StructuredQuery::Filter
|
28
|
+
attr_accessor :filter
|
29
|
+
|
30
|
+
##
|
31
|
+
# Create a Filter object.
|
32
|
+
#
|
33
|
+
# @param field [FieldPath, String, Symbol] A field path to filter
|
34
|
+
# results with.
|
35
|
+
# If a {FieldPath} object is not provided then the field will be
|
36
|
+
# treated as a dotted string, meaning the string represents individual
|
37
|
+
# fields joined by ".". Fields containing `~`, `*`, `/`, `[`, `]`, and
|
38
|
+
# `.` cannot be in a dotted string, and should provided using a
|
39
|
+
# {FieldPath} object instead.
|
40
|
+
#
|
41
|
+
# @param operator [String, Symbol] The operation to compare the field
|
42
|
+
# to. Acceptable values include:
|
43
|
+
# * less than: `<`, `lt`
|
44
|
+
# * less than or equal: `<=`, `lte`
|
45
|
+
# * greater than: `>`, `gt`
|
46
|
+
# * greater than or equal: `>=`, `gte`
|
47
|
+
# * equal: `=`, `==`, `eq`, `eql`, `is`
|
48
|
+
# * not equal: `!=`
|
49
|
+
# * in: `in`
|
50
|
+
# * not in: `not-in`, `not_in`
|
51
|
+
# * array contains: `array-contains`, `array_contains`
|
52
|
+
#
|
53
|
+
# @param value [Object] The value to compare the property to. Defaults to nil.
|
54
|
+
# Possible values are:
|
55
|
+
# * Integer
|
56
|
+
# * Float/BigDecimal
|
57
|
+
# * String
|
58
|
+
# * Boolean
|
59
|
+
# * Array
|
60
|
+
# * Date/Time
|
61
|
+
# * StringIO
|
62
|
+
# * Google::Cloud::Datastore::Key
|
63
|
+
# * Google::Cloud::Datastore::Entity
|
64
|
+
# * nil
|
65
|
+
#
|
66
|
+
# @return [Google::Cloud::Firestore::Filter] New filter for the given condition
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# require "google/cloud/firestore"
|
70
|
+
#
|
71
|
+
# firestore = Google::Cloud::Firestore.new
|
72
|
+
#
|
73
|
+
# # Create a Filter
|
74
|
+
# Google::Cloud::Firestore::Filter.new(:population, :>=, 1000000)
|
75
|
+
#
|
76
|
+
def initialize field, operator, value
|
77
|
+
@filter = create_filter field, operator, value
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Joins filter using AND operator.
|
82
|
+
#
|
83
|
+
# @overload where(filter)
|
84
|
+
# Pass Firestore::Filter to `where` via field_or_filter argument.
|
85
|
+
#
|
86
|
+
# @param filter [::Google::Cloud::Firestore::Filter]
|
87
|
+
#
|
88
|
+
# @overload where(field, operator, value)
|
89
|
+
# Pass arguments to `where` via positional arguments.
|
90
|
+
#
|
91
|
+
# @param field [FieldPath, String, Symbol] A field path to filter
|
92
|
+
# results with.
|
93
|
+
# If a {FieldPath} object is not provided then the field will be
|
94
|
+
# treated as a dotted string, meaning the string represents individual
|
95
|
+
# fields joined by ".". Fields containing `~`, `*`, `/`, `[`, `]`, and
|
96
|
+
# `.` cannot be in a dotted string, and should provided using a
|
97
|
+
# {FieldPath} object instead.
|
98
|
+
#
|
99
|
+
# @param operator [String, Symbol] The operation to compare the field
|
100
|
+
# to. Acceptable values include:
|
101
|
+
# * less than: `<`, `lt`
|
102
|
+
# * less than or equal: `<=`, `lte`
|
103
|
+
# * greater than: `>`, `gt`
|
104
|
+
# * greater than or equal: `>=`, `gte`
|
105
|
+
# * equal: `=`, `==`, `eq`, `eql`, `is`
|
106
|
+
# * not equal: `!=`
|
107
|
+
# * in: `in`
|
108
|
+
# * not in: `not-in`, `not_in`
|
109
|
+
# * array contains: `array-contains`, `array_contains`
|
110
|
+
#
|
111
|
+
# @param value [Object] The value to compare the property to. Defaults to nil.
|
112
|
+
# Possible values are:
|
113
|
+
# * Integer
|
114
|
+
# * Float/BigDecimal
|
115
|
+
# * String
|
116
|
+
# * Boolean
|
117
|
+
# * Array
|
118
|
+
# * Date/Time
|
119
|
+
# * StringIO
|
120
|
+
# * Google::Cloud::Datastore::Key
|
121
|
+
# * Google::Cloud::Datastore::Entity
|
122
|
+
# * nil
|
123
|
+
#
|
124
|
+
# @return [Filter] New Filter object.
|
125
|
+
#
|
126
|
+
# @example Pass a Filter type object in argument
|
127
|
+
# require "google/cloud/firestore"
|
128
|
+
#
|
129
|
+
# filter_1 = Google::Cloud::Firestore.Firestore.new(:population, :>=, 1000000)
|
130
|
+
# filter_2 = Google::Cloud::Firestore.Firestore.new("done", "=", "false")
|
131
|
+
#
|
132
|
+
# filter = filter_1.and(filter_2)
|
133
|
+
#
|
134
|
+
# @example Pass filter conditions in the argument
|
135
|
+
# require "google/cloud/firestore"
|
136
|
+
#
|
137
|
+
# filter_1 = Google::Cloud::Firestore.Firestore.new(:population, :>=, 1000000)
|
138
|
+
#
|
139
|
+
# filter = filter_1.and("done", "=", "false")
|
140
|
+
#
|
141
|
+
def and filter_or_field = nil, operator = nil, value = nil
|
142
|
+
combine_filters composite_filter_and, filter_or_field, operator, value
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Joins filter using OR operator.
|
147
|
+
#
|
148
|
+
# @overload where(filter)
|
149
|
+
# Pass Firestore::Filter to `where` via field_or_filter argument.
|
150
|
+
#
|
151
|
+
# @param filter [::Google::Cloud::Firestore::Filter]
|
152
|
+
#
|
153
|
+
# @overload where(field, operator, value)
|
154
|
+
# Pass arguments to `where` via positional arguments.
|
155
|
+
#
|
156
|
+
# @param field [FieldPath, String, Symbol] A field path to filter
|
157
|
+
# results with.
|
158
|
+
# If a {FieldPath} object is not provided then the field will be
|
159
|
+
# treated as a dotted string, meaning the string represents individual
|
160
|
+
# fields joined by ".". Fields containing `~`, `*`, `/`, `[`, `]`, and
|
161
|
+
# `.` cannot be in a dotted string, and should provided using a
|
162
|
+
# {FieldPath} object instead.
|
163
|
+
#
|
164
|
+
# @param operator [String, Symbol] The operation to compare the field
|
165
|
+
# to. Acceptable values include:
|
166
|
+
# * less than: `<`, `lt`
|
167
|
+
# * less than or equal: `<=`, `lte`
|
168
|
+
# * greater than: `>`, `gt`
|
169
|
+
# * greater than or equal: `>=`, `gte`
|
170
|
+
# * equal: `=`, `==`, `eq`, `eql`, `is`
|
171
|
+
# * not equal: `!=`
|
172
|
+
# * in: `in`
|
173
|
+
# * not in: `not-in`, `not_in`
|
174
|
+
# * array contains: `array-contains`, `array_contains`
|
175
|
+
#
|
176
|
+
# @param value [Object] The value to compare the property to. Defaults to nil.
|
177
|
+
# Possible values are:
|
178
|
+
# * Integer
|
179
|
+
# * Float/BigDecimal
|
180
|
+
# * String
|
181
|
+
# * Boolean
|
182
|
+
# * Array
|
183
|
+
# * Date/Time
|
184
|
+
# * StringIO
|
185
|
+
# * Google::Cloud::Datastore::Key
|
186
|
+
# * Google::Cloud::Datastore::Entity
|
187
|
+
# * nil
|
188
|
+
#
|
189
|
+
# @return [Filter] New Filter object.
|
190
|
+
#
|
191
|
+
# @example Pass a Filter type object in argument
|
192
|
+
# require "google/cloud/firestore"
|
193
|
+
#
|
194
|
+
# filter_1 = Google::Cloud::Firestore.Firestore.new(:population, :>=, 1000000)
|
195
|
+
# filter_2 = Google::Cloud::Firestore.Firestore.new("done", "=", "false")
|
196
|
+
#
|
197
|
+
# filter = filter_1.or(filter_2)
|
198
|
+
#
|
199
|
+
# @example Pass filter conditions in the argument
|
200
|
+
# require "google/cloud/firestore"
|
201
|
+
#
|
202
|
+
# filter_1 = Google::Cloud::Firestore.Firestore.new(:population, :>=, 1000000)
|
203
|
+
#
|
204
|
+
# filter = filter_1.or("done", "=", "false")
|
205
|
+
#
|
206
|
+
def or filter_or_field = nil, operator = nil, value = nil
|
207
|
+
combine_filters composite_filter_or, filter_or_field, operator, value
|
208
|
+
end
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
##
|
213
|
+
# @private
|
214
|
+
StructuredQuery = Google::Cloud::Firestore::V1::StructuredQuery
|
215
|
+
|
216
|
+
##
|
217
|
+
# @private
|
218
|
+
FILTER_OPS = {
|
219
|
+
"<" => :LESS_THAN,
|
220
|
+
"lt" => :LESS_THAN,
|
221
|
+
"<=" => :LESS_THAN_OR_EQUAL,
|
222
|
+
"lte" => :LESS_THAN_OR_EQUAL,
|
223
|
+
">" => :GREATER_THAN,
|
224
|
+
"gt" => :GREATER_THAN,
|
225
|
+
">=" => :GREATER_THAN_OR_EQUAL,
|
226
|
+
"gte" => :GREATER_THAN_OR_EQUAL,
|
227
|
+
"=" => :EQUAL,
|
228
|
+
"==" => :EQUAL,
|
229
|
+
"eq" => :EQUAL,
|
230
|
+
"eql" => :EQUAL,
|
231
|
+
"is" => :EQUAL,
|
232
|
+
"!=" => :NOT_EQUAL,
|
233
|
+
"array_contains" => :ARRAY_CONTAINS,
|
234
|
+
"array-contains" => :ARRAY_CONTAINS,
|
235
|
+
"include" => :ARRAY_CONTAINS,
|
236
|
+
"include?" => :ARRAY_CONTAINS,
|
237
|
+
"has" => :ARRAY_CONTAINS,
|
238
|
+
"in" => :IN,
|
239
|
+
"not_in" => :NOT_IN,
|
240
|
+
"not-in" => :NOT_IN,
|
241
|
+
"array_contains_any" => :ARRAY_CONTAINS_ANY,
|
242
|
+
"array-contains-any" => :ARRAY_CONTAINS_ANY
|
243
|
+
}.freeze
|
244
|
+
|
245
|
+
##
|
246
|
+
# @private
|
247
|
+
INEQUALITY_FILTERS = [
|
248
|
+
:LESS_THAN,
|
249
|
+
:LESS_THAN_OR_EQUAL,
|
250
|
+
:GREATER_THAN,
|
251
|
+
:GREATER_THAN_OR_EQUAL
|
252
|
+
].freeze
|
253
|
+
|
254
|
+
def composite_filter_and
|
255
|
+
StructuredQuery::Filter.new(
|
256
|
+
composite_filter: StructuredQuery::CompositeFilter.new(op: :AND)
|
257
|
+
)
|
258
|
+
end
|
259
|
+
|
260
|
+
def composite_filter_or
|
261
|
+
StructuredQuery::Filter.new(
|
262
|
+
composite_filter: StructuredQuery::CompositeFilter.new(op: :OR)
|
263
|
+
)
|
264
|
+
end
|
265
|
+
|
266
|
+
def combine_filters new_filter, filter_or_field, operator, value
|
267
|
+
new_filter.composite_filter.filters << @filter
|
268
|
+
new_filter.composite_filter.filters << if filter_or_field.is_a? Google::Cloud::Firestore::Filter
|
269
|
+
filter_or_field.filter
|
270
|
+
else
|
271
|
+
create_filter filter_or_field, operator, value
|
272
|
+
end
|
273
|
+
dup.tap do |f|
|
274
|
+
f.filter = new_filter
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def value_nil? value
|
279
|
+
[nil, :null, :nil].include? value
|
280
|
+
end
|
281
|
+
|
282
|
+
def value_nan? value
|
283
|
+
# Comparing NaN values raises, so check for #nan? first.
|
284
|
+
return true if value.respond_to?(:nan?) && value.nan?
|
285
|
+
[:nan].include? value
|
286
|
+
end
|
287
|
+
|
288
|
+
def value_unary? value
|
289
|
+
value_nil?(value) || value_nan?(value)
|
290
|
+
end
|
291
|
+
|
292
|
+
def create_filter field, op_key, value
|
293
|
+
return if field.nil? && op_key.nil? && value.nil?
|
294
|
+
field = FieldPath.parse field unless field.is_a? FieldPath
|
295
|
+
field = StructuredQuery::FieldReference.new field_path: field.formatted_string.to_s
|
296
|
+
operator = FILTER_OPS[op_key.to_s.downcase]
|
297
|
+
raise ArgumentError, "unknown operator #{op_key}" if operator.nil?
|
298
|
+
|
299
|
+
if value_unary? value
|
300
|
+
operator = case operator
|
301
|
+
when :EQUAL
|
302
|
+
value_nan?(value) ? :IS_NAN : :IS_NULL
|
303
|
+
when :NOT_EQUAL
|
304
|
+
value_nan?(value) ? :IS_NOT_NAN : :IS_NOT_NULL
|
305
|
+
else
|
306
|
+
raise ArgumentError, "can only perform '==' and '!=' comparisons on #{value} values"
|
307
|
+
end
|
308
|
+
|
309
|
+
return StructuredQuery::Filter.new(
|
310
|
+
unary_filter: StructuredQuery::UnaryFilter.new(
|
311
|
+
field: field, op: operator
|
312
|
+
)
|
313
|
+
)
|
314
|
+
end
|
315
|
+
|
316
|
+
value = Convert.raw_to_value value
|
317
|
+
StructuredQuery::Filter.new(
|
318
|
+
field_filter: StructuredQuery::FieldFilter.new(
|
319
|
+
field: field, op: operator, value: value
|
320
|
+
)
|
321
|
+
)
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# Copyright 2023 Google LLC
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Google
|
16
|
+
module Cloud
|
17
|
+
module Firestore
|
18
|
+
module Promise
|
19
|
+
##
|
20
|
+
# # Future
|
21
|
+
#
|
22
|
+
# A Future object represents a value which will become available in future.
|
23
|
+
# May reject with a reason instead, e.g. when the tasks raises an exception.
|
24
|
+
#
|
25
|
+
class Future
|
26
|
+
##
|
27
|
+
# Initialize the future object
|
28
|
+
#
|
29
|
+
def initialize future
|
30
|
+
@future = future
|
31
|
+
end
|
32
|
+
|
33
|
+
# Is it in fulfilled state?
|
34
|
+
#
|
35
|
+
# @return [Boolean]
|
36
|
+
def fulfilled?
|
37
|
+
@future.fulfilled?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Is it in rejected state?
|
41
|
+
#
|
42
|
+
# @return [Boolean]
|
43
|
+
def rejected?
|
44
|
+
@future.rejected?
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Method waits for the timeout duration and return the value of the future if
|
49
|
+
# fulfilled, timeout value in case of timeout and nil in case of rejection.
|
50
|
+
#
|
51
|
+
# @param [Integer] timeout the maximum time in seconds to wait
|
52
|
+
# @param [Object] timeout_value a value returned by the method when it times out
|
53
|
+
# @return [Object, nil, timeout_value] the value of the Future when fulfilled,
|
54
|
+
# timeout_value on timeout, nil on rejection.
|
55
|
+
def value timeout = nil, timeout_value = nil
|
56
|
+
@future.value timeout, timeout_value
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns reason of future's rejection.
|
60
|
+
#
|
61
|
+
# @return [Object, timeout_value] the reason, or timeout_value on timeout, or nil on fulfillment.
|
62
|
+
def reason timeout = nil, timeout_value = nil
|
63
|
+
@future.reason timeout, timeout_value
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# Method waits for the timeout duration and raise exception on rejection
|
68
|
+
#
|
69
|
+
# @param [Integer] timeout the maximum time in seconds to wait
|
70
|
+
def wait! timeout = nil
|
71
|
+
@future.wait! timeout
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Chains the task to be executed synchronously after it fulfills. Does not run
|
76
|
+
# the task if it rejects. It will resolve though, triggering any dependent futures.
|
77
|
+
#
|
78
|
+
# @return [Future]
|
79
|
+
# @yield [reason, *args] to the task.
|
80
|
+
def then(*args, &task)
|
81
|
+
Future.new @future.then(*args, &task)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Chains the task to be executed synchronously on executor after it rejects. Does
|
85
|
+
# not run the task if it fulfills. It will resolve though, triggering any
|
86
|
+
# dependent futures.
|
87
|
+
#
|
88
|
+
# @return [Future]
|
89
|
+
# @yield [reason, *args] to the task.
|
90
|
+
def rescue(*args, &task)
|
91
|
+
Future.new @future.rescue(*args, &task)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -18,6 +18,7 @@ require "google/cloud/firestore/document_snapshot"
|
|
18
18
|
require "google/cloud/firestore/query_listener"
|
19
19
|
require "google/cloud/firestore/convert"
|
20
20
|
require "google/cloud/firestore/aggregate_query"
|
21
|
+
require "google/cloud/firestore/filter"
|
21
22
|
require "json"
|
22
23
|
|
23
24
|
module Google
|
@@ -210,29 +211,48 @@ module Google
|
|
210
211
|
end
|
211
212
|
|
212
213
|
##
|
213
|
-
#
|
214
|
-
#
|
215
|
-
# @
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
#
|
220
|
-
#
|
221
|
-
#
|
222
|
-
#
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
227
|
-
#
|
228
|
-
#
|
229
|
-
#
|
230
|
-
#
|
231
|
-
#
|
232
|
-
#
|
233
|
-
#
|
234
|
-
#
|
235
|
-
#
|
214
|
+
# Adds filter to the where clause
|
215
|
+
#
|
216
|
+
# @overload where(filter)
|
217
|
+
# Pass Firestore::Filter to `where` via field_or_filter argument.
|
218
|
+
#
|
219
|
+
# @param filter [::Google::Cloud::Firestore::Filter]
|
220
|
+
#
|
221
|
+
# @overload where(field, operator, value)
|
222
|
+
# Pass arguments to `where` via positional arguments.
|
223
|
+
#
|
224
|
+
# @param field [FieldPath, String, Symbol] A field path to filter
|
225
|
+
# results with.
|
226
|
+
# If a {FieldPath} object is not provided then the field will be
|
227
|
+
# treated as a dotted string, meaning the string represents individual
|
228
|
+
# fields joined by ".". Fields containing `~`, `*`, `/`, `[`, `]`, and
|
229
|
+
# `.` cannot be in a dotted string, and should provided using a
|
230
|
+
# {FieldPath} object instead.
|
231
|
+
#
|
232
|
+
# @param operator [String, Symbol] The operation to compare the field
|
233
|
+
# to. Acceptable values include:
|
234
|
+
# * less than: `<`, `lt`
|
235
|
+
# * less than or equal: `<=`, `lte`
|
236
|
+
# * greater than: `>`, `gt`
|
237
|
+
# * greater than or equal: `>=`, `gte`
|
238
|
+
# * equal: `=`, `==`, `eq`, `eql`, `is`
|
239
|
+
# * not equal: `!=`
|
240
|
+
# * in: `in`
|
241
|
+
# * not in: `not-in`, `not_in`
|
242
|
+
# * array contains: `array-contains`, `array_contains`
|
243
|
+
#
|
244
|
+
# @param value [Object] The value to compare the property to. Defaults to nil.
|
245
|
+
# Possible values are:
|
246
|
+
# * Integer
|
247
|
+
# * Float/BigDecimal
|
248
|
+
# * String
|
249
|
+
# * Boolean
|
250
|
+
# * Array
|
251
|
+
# * Date/Time
|
252
|
+
# * StringIO
|
253
|
+
# * Google::Cloud::Datastore::Key
|
254
|
+
# * Google::Cloud::Datastore::Entity
|
255
|
+
# * nil
|
236
256
|
#
|
237
257
|
# @return [Query] New query with `where` called on it.
|
238
258
|
#
|
@@ -251,7 +271,25 @@ module Google
|
|
251
271
|
# puts "#{city.document_id} has #{city[:population]} residents."
|
252
272
|
# end
|
253
273
|
#
|
254
|
-
|
274
|
+
# @example
|
275
|
+
# require "google/cloud/firestore"
|
276
|
+
#
|
277
|
+
# firestore = Google::Cloud::Firestore.new
|
278
|
+
#
|
279
|
+
# # Get a collection reference
|
280
|
+
# cities_col = firestore.col "cities"
|
281
|
+
#
|
282
|
+
# # Create a filter
|
283
|
+
# filter = Filter.create(:population, :>=, 1000000)
|
284
|
+
#
|
285
|
+
# # Add filter to where clause
|
286
|
+
# query = query.where filter
|
287
|
+
#
|
288
|
+
# query.get do |city|
|
289
|
+
# puts "#{city.document_id} has #{city[:population]} residents."
|
290
|
+
# end
|
291
|
+
#
|
292
|
+
def where filter_or_field = nil, operator = nil, value = nil
|
255
293
|
if query_has_cursors?
|
256
294
|
raise "cannot call where after calling " \
|
257
295
|
"start_at, start_after, end_before, or end_at"
|
@@ -260,10 +298,12 @@ module Google
|
|
260
298
|
new_query = @query.dup
|
261
299
|
new_query ||= StructuredQuery.new
|
262
300
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
301
|
+
if filter_or_field.is_a? Google::Cloud::Firestore::Filter
|
302
|
+
new_query.where = filter_or_field.filter
|
303
|
+
else
|
304
|
+
new_filter = Google::Cloud::Firestore::Filter.new filter_or_field, operator, value
|
305
|
+
add_filters_to_query new_query, new_filter.filter
|
306
|
+
end
|
267
307
|
|
268
308
|
Query.start new_query, parent_path, client, limit_type: limit_type
|
269
309
|
end
|
@@ -1087,34 +1127,6 @@ module Google
|
|
1087
1127
|
# @private
|
1088
1128
|
StructuredQuery = Google::Cloud::Firestore::V1::StructuredQuery
|
1089
1129
|
|
1090
|
-
##
|
1091
|
-
# @private
|
1092
|
-
FILTER_OPS = {
|
1093
|
-
"<" => :LESS_THAN,
|
1094
|
-
"lt" => :LESS_THAN,
|
1095
|
-
"<=" => :LESS_THAN_OR_EQUAL,
|
1096
|
-
"lte" => :LESS_THAN_OR_EQUAL,
|
1097
|
-
">" => :GREATER_THAN,
|
1098
|
-
"gt" => :GREATER_THAN,
|
1099
|
-
">=" => :GREATER_THAN_OR_EQUAL,
|
1100
|
-
"gte" => :GREATER_THAN_OR_EQUAL,
|
1101
|
-
"=" => :EQUAL,
|
1102
|
-
"==" => :EQUAL,
|
1103
|
-
"eq" => :EQUAL,
|
1104
|
-
"eql" => :EQUAL,
|
1105
|
-
"is" => :EQUAL,
|
1106
|
-
"!=" => :NOT_EQUAL,
|
1107
|
-
"array_contains" => :ARRAY_CONTAINS,
|
1108
|
-
"array-contains" => :ARRAY_CONTAINS,
|
1109
|
-
"include" => :ARRAY_CONTAINS,
|
1110
|
-
"include?" => :ARRAY_CONTAINS,
|
1111
|
-
"has" => :ARRAY_CONTAINS,
|
1112
|
-
"in" => :IN,
|
1113
|
-
"not_in" => :NOT_IN,
|
1114
|
-
"not-in" => :NOT_IN,
|
1115
|
-
"array_contains_any" => :ARRAY_CONTAINS_ANY,
|
1116
|
-
"array-contains-any" => :ARRAY_CONTAINS_ANY
|
1117
|
-
}.freeze
|
1118
1130
|
##
|
1119
1131
|
# @private
|
1120
1132
|
INEQUALITY_FILTERS = [
|
@@ -1138,36 +1150,6 @@ module Google
|
|
1138
1150
|
value_nil?(value) || value_nan?(value)
|
1139
1151
|
end
|
1140
1152
|
|
1141
|
-
def filter name, op_key, value
|
1142
|
-
field = StructuredQuery::FieldReference.new field_path: name.to_s
|
1143
|
-
operator = FILTER_OPS[op_key.to_s.downcase]
|
1144
|
-
raise ArgumentError, "unknown operator #{op_key}" if operator.nil?
|
1145
|
-
|
1146
|
-
if value_unary? value
|
1147
|
-
operator = case operator
|
1148
|
-
when :EQUAL
|
1149
|
-
value_nan?(value) ? :IS_NAN : :IS_NULL
|
1150
|
-
when :NOT_EQUAL
|
1151
|
-
value_nan?(value) ? :IS_NOT_NAN : :IS_NOT_NULL
|
1152
|
-
else
|
1153
|
-
raise ArgumentError, "can only perform '==' and '!=' comparisons on #{value} values"
|
1154
|
-
end
|
1155
|
-
|
1156
|
-
return StructuredQuery::Filter.new(
|
1157
|
-
unary_filter: StructuredQuery::UnaryFilter.new(
|
1158
|
-
field: field, op: operator
|
1159
|
-
)
|
1160
|
-
)
|
1161
|
-
end
|
1162
|
-
|
1163
|
-
value = Convert.raw_to_value value
|
1164
|
-
StructuredQuery::Filter.new(
|
1165
|
-
field_filter: StructuredQuery::FieldFilter.new(
|
1166
|
-
field: field, op: operator, value: value
|
1167
|
-
)
|
1168
|
-
)
|
1169
|
-
end
|
1170
|
-
|
1171
1153
|
def composite_filter
|
1172
1154
|
StructuredQuery::Filter.new(
|
1173
1155
|
composite_filter: StructuredQuery::CompositeFilter.new(op: :AND)
|