google-cloud-firestore 2.1.0 → 2.5.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 +38 -0
- data/CONTRIBUTING.md +2 -2
- data/LOGGING.md +1 -1
- data/lib/google-cloud-firestore.rb +1 -0
- data/lib/google/cloud/firestore/batch.rb +3 -4
- data/lib/google/cloud/firestore/client.rb +10 -10
- data/lib/google/cloud/firestore/collection_reference_list.rb +3 -3
- data/lib/google/cloud/firestore/convert.rb +151 -173
- data/lib/google/cloud/firestore/document_listener.rb +86 -7
- data/lib/google/cloud/firestore/document_reference.rb +3 -4
- data/lib/google/cloud/firestore/document_reference/list.rb +4 -5
- data/lib/google/cloud/firestore/document_snapshot.rb +1 -2
- data/lib/google/cloud/firestore/field_path.rb +2 -2
- data/lib/google/cloud/firestore/query.rb +22 -20
- data/lib/google/cloud/firestore/query_listener.rb +82 -1
- data/lib/google/cloud/firestore/service.rb +4 -1
- data/lib/google/cloud/firestore/transaction.rb +5 -5
- data/lib/google/cloud/firestore/version.rb +1 -1
- data/lib/google/cloud/firestore/watch/inventory.rb +9 -8
- data/lib/google/cloud/firestore/watch/listener.rb +24 -17
- metadata +6 -6
@@ -14,11 +14,14 @@
|
|
14
14
|
|
15
15
|
|
16
16
|
require "google/cloud/firestore/watch/listener"
|
17
|
+
require "monitor"
|
17
18
|
|
18
19
|
module Google
|
19
20
|
module Cloud
|
20
21
|
module Firestore
|
21
22
|
##
|
23
|
+
# # DocumentListener
|
24
|
+
#
|
22
25
|
# An ongoing listen operation on a document reference. This is returned by
|
23
26
|
# calling {DocumentReference#listen}.
|
24
27
|
#
|
@@ -31,25 +34,28 @@ module Google
|
|
31
34
|
# nyc_ref = firestore.doc "cities/NYC"
|
32
35
|
#
|
33
36
|
# listener = nyc_ref.listen do |snapshot|
|
34
|
-
# puts "The population of #{snapshot[:name]} "
|
35
|
-
# puts "is #{snapshot[:population]}."
|
37
|
+
# puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
|
36
38
|
# end
|
37
39
|
#
|
38
40
|
# # When ready, stop the listen operation and close the stream.
|
39
41
|
# listener.stop
|
40
42
|
#
|
41
43
|
class DocumentListener
|
44
|
+
include MonitorMixin
|
42
45
|
##
|
43
46
|
# @private
|
44
47
|
# Creates the watch stream and listener object.
|
45
48
|
def initialize doc_ref, &callback
|
49
|
+
super() # to init MonitorMixin
|
50
|
+
|
46
51
|
@doc_ref = doc_ref
|
47
52
|
raise ArgumentError if @doc_ref.nil?
|
48
53
|
|
49
54
|
@callback = callback
|
50
55
|
raise ArgumentError if @callback.nil?
|
56
|
+
@error_callbacks = []
|
51
57
|
|
52
|
-
@listener = Watch::Listener.for_doc_ref doc_ref do |query_snp|
|
58
|
+
@listener = Watch::Listener.for_doc_ref self, doc_ref do |query_snp|
|
53
59
|
doc_snp = query_snp.docs.find { |doc| doc.path == @doc_ref.path }
|
54
60
|
|
55
61
|
if doc_snp.nil?
|
@@ -80,8 +86,7 @@ module Google
|
|
80
86
|
# nyc_ref = firestore.doc "cities/NYC"
|
81
87
|
#
|
82
88
|
# listener = nyc_ref.listen do |snapshot|
|
83
|
-
# puts "The population of #{snapshot[:name]} "
|
84
|
-
# puts "is #{snapshot[:population]}."
|
89
|
+
# puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
|
85
90
|
# end
|
86
91
|
#
|
87
92
|
# # When ready, stop the listen operation and close the stream.
|
@@ -103,8 +108,7 @@ module Google
|
|
103
108
|
# nyc_ref = firestore.doc "cities/NYC"
|
104
109
|
#
|
105
110
|
# listener = nyc_ref.listen do |snapshot|
|
106
|
-
# puts "The population of #{snapshot[:name]} "
|
107
|
-
# puts "is #{snapshot[:population]}."
|
111
|
+
# puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
|
108
112
|
# end
|
109
113
|
#
|
110
114
|
# # Checks if the listener is stopped.
|
@@ -119,6 +123,81 @@ module Google
|
|
119
123
|
def stopped?
|
120
124
|
@listener.stopped?
|
121
125
|
end
|
126
|
+
|
127
|
+
##
|
128
|
+
# Register to be notified of errors when raised.
|
129
|
+
#
|
130
|
+
# If an unhandled error has occurred the listener will attempt to
|
131
|
+
# recover from the error and resume listening.
|
132
|
+
#
|
133
|
+
# Multiple error handlers can be added.
|
134
|
+
#
|
135
|
+
# @yield [callback] The block to be called when an error is raised.
|
136
|
+
# @yieldparam [Exception] error The error raised.
|
137
|
+
#
|
138
|
+
# @example
|
139
|
+
# require "google/cloud/firestore"
|
140
|
+
#
|
141
|
+
# firestore = Google::Cloud::Firestore.new
|
142
|
+
#
|
143
|
+
# # Get a document reference
|
144
|
+
# nyc_ref = firestore.doc "cities/NYC"
|
145
|
+
#
|
146
|
+
# listener = nyc_ref.listen do |snapshot|
|
147
|
+
# puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
# # Register to be notified when unhandled errors occur.
|
151
|
+
# listener.on_error do |error|
|
152
|
+
# puts error
|
153
|
+
# end
|
154
|
+
#
|
155
|
+
# # When ready, stop the listen operation and close the stream.
|
156
|
+
# listener.stop
|
157
|
+
#
|
158
|
+
def on_error &block
|
159
|
+
raise ArgumentError, "on_error must be called with a block" unless block_given?
|
160
|
+
synchronize { @error_callbacks << block }
|
161
|
+
end
|
162
|
+
|
163
|
+
##
|
164
|
+
# The most recent unhandled error to occur while listening for changes.
|
165
|
+
#
|
166
|
+
# If an unhandled error has occurred the listener will attempt to
|
167
|
+
# recover from the error and resume listening.
|
168
|
+
#
|
169
|
+
# @return [Exception, nil] error The most recent error raised.
|
170
|
+
#
|
171
|
+
# @example
|
172
|
+
# require "google/cloud/firestore"
|
173
|
+
#
|
174
|
+
# firestore = Google::Cloud::Firestore.new
|
175
|
+
#
|
176
|
+
# # Get a document reference
|
177
|
+
# nyc_ref = firestore.doc "cities/NYC"
|
178
|
+
#
|
179
|
+
# listener = nyc_ref.listen do |snapshot|
|
180
|
+
# puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# # If an error was raised, it can be retrieved here:
|
184
|
+
# listener.last_error #=> nil
|
185
|
+
#
|
186
|
+
# # When ready, stop the listen operation and close the stream.
|
187
|
+
# listener.stop
|
188
|
+
#
|
189
|
+
def last_error
|
190
|
+
synchronize { @last_error }
|
191
|
+
end
|
192
|
+
|
193
|
+
# @private Pass the error to user-provided error callbacks.
|
194
|
+
def error! error
|
195
|
+
error_callbacks = synchronize do
|
196
|
+
@last_error = error
|
197
|
+
@error_callbacks.dup
|
198
|
+
end
|
199
|
+
error_callbacks.each { |error_callback| error_callback.call error }
|
200
|
+
end
|
122
201
|
end
|
123
202
|
end
|
124
203
|
end
|
@@ -90,11 +90,11 @@ module Google
|
|
90
90
|
# puts col.collection_id
|
91
91
|
# end
|
92
92
|
#
|
93
|
-
def cols
|
93
|
+
def cols &block
|
94
94
|
ensure_service!
|
95
95
|
grpc = service.list_collections path
|
96
96
|
cols_enum = CollectionReferenceList.from_grpc(grpc, client, path).all
|
97
|
-
cols_enum.each
|
97
|
+
cols_enum.each(&block) if block_given?
|
98
98
|
cols_enum
|
99
99
|
end
|
100
100
|
alias collections cols
|
@@ -168,8 +168,7 @@ module Google
|
|
168
168
|
# nyc_ref = firestore.doc "cities/NYC"
|
169
169
|
#
|
170
170
|
# listener = nyc_ref.listen do |snapshot|
|
171
|
-
# puts "The population of #{snapshot[:name]} "
|
172
|
-
# puts "is #{snapshot[:population]}."
|
171
|
+
# puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
|
173
172
|
# end
|
174
173
|
#
|
175
174
|
# # When ready, stop the listen operation and close the stream.
|
@@ -86,8 +86,7 @@ module Google
|
|
86
86
|
def next
|
87
87
|
return nil unless next?
|
88
88
|
ensure_client!
|
89
|
-
|
90
|
-
grpc = @client.service.list_documents @parent, @collection_id, options
|
89
|
+
grpc = @client.service.list_documents @parent, @collection_id, token: token, max: @max
|
91
90
|
self.class.from_grpc grpc, @client, @parent, @collection_id, @max
|
92
91
|
end
|
93
92
|
|
@@ -143,17 +142,17 @@ module Google
|
|
143
142
|
# puts doc_ref.document_id
|
144
143
|
# end
|
145
144
|
#
|
146
|
-
def all request_limit: nil
|
145
|
+
def all request_limit: nil, &block
|
147
146
|
request_limit = request_limit.to_i if request_limit
|
148
147
|
unless block_given?
|
149
148
|
return enum_for :all, request_limit: request_limit
|
150
149
|
end
|
151
150
|
results = self
|
152
151
|
loop do
|
153
|
-
results.each
|
152
|
+
results.each(&block)
|
154
153
|
if request_limit
|
155
154
|
request_limit -= 1
|
156
|
-
break if request_limit
|
155
|
+
break if request_limit.negative?
|
157
156
|
end
|
158
157
|
break unless results.next?
|
159
158
|
results = results.next
|
@@ -53,8 +53,7 @@ module Google
|
|
53
53
|
# nyc_ref = firestore.doc "cities/NYC"
|
54
54
|
#
|
55
55
|
# listener = nyc_ref.listen do |snapshot|
|
56
|
-
# puts "The population of #{snapshot[:name]} "
|
57
|
-
# puts "is #{snapshot[:population]}."
|
56
|
+
# puts "The population of #{snapshot[:name]} is #{snapshot[:population]}."
|
58
57
|
# end
|
59
58
|
#
|
60
59
|
# # When ready, stop the listen operation and close the stream.
|
@@ -210,14 +210,14 @@ module Google
|
|
210
210
|
protected
|
211
211
|
|
212
212
|
START_FIELD_PATH_CHARS = /\A[a-zA-Z_]/.freeze
|
213
|
-
INVALID_FIELD_PATH_CHARS = %r{[
|
213
|
+
INVALID_FIELD_PATH_CHARS = %r{[~*/\[\]]}.freeze
|
214
214
|
|
215
215
|
def escape_field_for_path field
|
216
216
|
field = String field
|
217
217
|
|
218
218
|
if INVALID_FIELD_PATH_CHARS.match(field) ||
|
219
219
|
field["."] || field["`"] || field["\\"]
|
220
|
-
escaped_field = field.gsub(/[
|
220
|
+
escaped_field = field.gsub(/[`\\]/, "`" => "\\\`", "\\" => "\\\\")
|
221
221
|
return "`#{escaped_field}`"
|
222
222
|
end
|
223
223
|
|
@@ -216,6 +216,9 @@ module Google
|
|
216
216
|
# * greater than: `>`, `gt`
|
217
217
|
# * greater than or equal: `>=`, `gte`
|
218
218
|
# * equal: `=`, `==`, `eq`, `eql`, `is`
|
219
|
+
# * not equal: `!=`
|
220
|
+
# * in: `in`
|
221
|
+
# * not in: `not-in`, `not_in`
|
219
222
|
# * array contains: `array-contains`, `array_contains`
|
220
223
|
# @param [Object] value A value the field is compared to.
|
221
224
|
#
|
@@ -993,28 +996,25 @@ module Google
|
|
993
996
|
"eq" => :EQUAL,
|
994
997
|
"eql" => :EQUAL,
|
995
998
|
"is" => :EQUAL,
|
999
|
+
"!=" => :NOT_EQUAL,
|
996
1000
|
"array_contains" => :ARRAY_CONTAINS,
|
997
1001
|
"array-contains" => :ARRAY_CONTAINS,
|
998
1002
|
"include" => :ARRAY_CONTAINS,
|
999
1003
|
"include?" => :ARRAY_CONTAINS,
|
1000
1004
|
"has" => :ARRAY_CONTAINS,
|
1001
1005
|
"in" => :IN,
|
1006
|
+
"not_in" => :NOT_IN,
|
1007
|
+
"not-in" => :NOT_IN,
|
1002
1008
|
"array_contains_any" => :ARRAY_CONTAINS_ANY,
|
1003
1009
|
"array-contains-any" => :ARRAY_CONTAINS_ANY
|
1004
1010
|
}.freeze
|
1005
1011
|
##
|
1006
1012
|
# @private
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
# @private
|
1013
|
-
INEQUALITY_FILTERS = %i[
|
1014
|
-
LESS_THAN
|
1015
|
-
LESS_THAN_OR_EQUAL
|
1016
|
-
GREATER_THAN
|
1017
|
-
GREATER_THAN_OR_EQUAL
|
1013
|
+
INEQUALITY_FILTERS = [
|
1014
|
+
:LESS_THAN,
|
1015
|
+
:LESS_THAN_OR_EQUAL,
|
1016
|
+
:GREATER_THAN,
|
1017
|
+
:GREATER_THAN_OR_EQUAL
|
1018
1018
|
].freeze
|
1019
1019
|
|
1020
1020
|
def value_nil? value
|
@@ -1031,18 +1031,20 @@ module Google
|
|
1031
1031
|
value_nil?(value) || value_nan?(value)
|
1032
1032
|
end
|
1033
1033
|
|
1034
|
-
def filter name,
|
1034
|
+
def filter name, op_key, value
|
1035
1035
|
field = StructuredQuery::FieldReference.new field_path: name.to_s
|
1036
|
-
operator = FILTER_OPS[
|
1037
|
-
raise ArgumentError, "unknown operator #{
|
1036
|
+
operator = FILTER_OPS[op_key.to_s.downcase]
|
1037
|
+
raise ArgumentError, "unknown operator #{op_key}" if operator.nil?
|
1038
1038
|
|
1039
1039
|
if value_unary? value
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1040
|
+
operator = case operator
|
1041
|
+
when :EQUAL
|
1042
|
+
value_nan?(value) ? :IS_NAN : :IS_NULL
|
1043
|
+
when :NOT_EQUAL
|
1044
|
+
value_nan?(value) ? :IS_NOT_NAN : :IS_NOT_NULL
|
1045
|
+
else
|
1046
|
+
raise ArgumentError, "can only perform '==' and '!=' comparisons on #{value} values"
|
1047
|
+
end
|
1046
1048
|
|
1047
1049
|
return StructuredQuery::Filter.new(
|
1048
1050
|
unary_filter: StructuredQuery::UnaryFilter.new(
|
@@ -41,17 +41,21 @@ module Google
|
|
41
41
|
# listener.stop
|
42
42
|
#
|
43
43
|
class QueryListener
|
44
|
+
include MonitorMixin
|
44
45
|
##
|
45
46
|
# @private
|
46
47
|
# Creates the watch stream and listener object.
|
47
48
|
def initialize query, &callback
|
49
|
+
super() # to init MonitorMixin
|
50
|
+
|
48
51
|
@query = query
|
49
52
|
raise ArgumentError if @query.nil?
|
50
53
|
|
51
54
|
@callback = callback
|
52
55
|
raise ArgumentError if @callback.nil?
|
56
|
+
@error_callbacks = []
|
53
57
|
|
54
|
-
@listener = Watch::Listener.for_query query, &callback
|
58
|
+
@listener = Watch::Listener.for_query self, query, &callback
|
55
59
|
end
|
56
60
|
|
57
61
|
##
|
@@ -112,6 +116,83 @@ module Google
|
|
112
116
|
def stopped?
|
113
117
|
@listener.stopped?
|
114
118
|
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# Register to be notified of errors when raised.
|
122
|
+
#
|
123
|
+
# If an unhandled error has occurred the listener will attempt to
|
124
|
+
# recover from the error and resume listening.
|
125
|
+
#
|
126
|
+
# Multiple error handlers can be added.
|
127
|
+
#
|
128
|
+
# @yield [callback] The block to be called when an error is raised.
|
129
|
+
# @yieldparam [Exception] error The error raised.
|
130
|
+
#
|
131
|
+
# @example
|
132
|
+
# require "google/cloud/firestore"
|
133
|
+
#
|
134
|
+
# firestore = Google::Cloud::Firestore.new
|
135
|
+
#
|
136
|
+
# # Create a query
|
137
|
+
# query = firestore.col(:cities).order(:population, :desc)
|
138
|
+
#
|
139
|
+
# listener = query.listen do |snapshot|
|
140
|
+
# puts "The query snapshot has #{snapshot.docs.count} documents "
|
141
|
+
# puts "and has #{snapshot.changes.count} changes."
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# # Register to be notified when unhandled errors occur.
|
145
|
+
# listener.on_error do |error|
|
146
|
+
# puts error
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# # When ready, stop the listen operation and close the stream.
|
150
|
+
# listener.stop
|
151
|
+
#
|
152
|
+
def on_error &block
|
153
|
+
raise ArgumentError, "on_error must be called with a block" unless block_given?
|
154
|
+
synchronize { @error_callbacks << block }
|
155
|
+
end
|
156
|
+
|
157
|
+
##
|
158
|
+
# The most recent unhandled error to occur while listening for changes.
|
159
|
+
#
|
160
|
+
# If an unhandled error has occurred the listener will attempt to
|
161
|
+
# recover from the error and resume listening.
|
162
|
+
#
|
163
|
+
# @return [Exception, nil] error The most recent error raised.
|
164
|
+
#
|
165
|
+
# @example
|
166
|
+
# require "google/cloud/firestore"
|
167
|
+
#
|
168
|
+
# firestore = Google::Cloud::Firestore.new
|
169
|
+
#
|
170
|
+
# # Create a query
|
171
|
+
# query = firestore.col(:cities).order(:population, :desc)
|
172
|
+
#
|
173
|
+
# listener = query.listen do |snapshot|
|
174
|
+
# puts "The query snapshot has #{snapshot.docs.count} documents "
|
175
|
+
# puts "and has #{snapshot.changes.count} changes."
|
176
|
+
# end
|
177
|
+
#
|
178
|
+
# # If an error was raised, it can be retrieved here:
|
179
|
+
# listener.last_error #=> nil
|
180
|
+
#
|
181
|
+
# # When ready, stop the listen operation and close the stream.
|
182
|
+
# listener.stop
|
183
|
+
#
|
184
|
+
def last_error
|
185
|
+
synchronize { @last_error }
|
186
|
+
end
|
187
|
+
|
188
|
+
# @private Pass the error to user-provided error callbacks.
|
189
|
+
def error! error
|
190
|
+
error_callbacks = synchronize do
|
191
|
+
@last_error = error
|
192
|
+
@error_callbacks.dup
|
193
|
+
end
|
194
|
+
error_callbacks.each { |error_callback| error_callback.call error }
|
195
|
+
end
|
115
196
|
end
|
116
197
|
end
|
117
198
|
end
|
@@ -26,7 +26,10 @@ module Google
|
|
26
26
|
# @private Represents the gRPC Firestore service, including all the API
|
27
27
|
# methods.
|
28
28
|
class Service
|
29
|
-
attr_accessor :project
|
29
|
+
attr_accessor :project
|
30
|
+
attr_accessor :credentials
|
31
|
+
attr_accessor :timeout
|
32
|
+
attr_accessor :host
|
30
33
|
|
31
34
|
##
|
32
35
|
# Creates a new Service instance.
|
@@ -131,7 +131,7 @@ module Google
|
|
131
131
|
ensure_service!
|
132
132
|
|
133
133
|
unless block_given?
|
134
|
-
return enum_for :get_all, docs, field_mask: field_mask
|
134
|
+
return enum_for :get_all, *docs, field_mask: field_mask
|
135
135
|
end
|
136
136
|
|
137
137
|
doc_paths = Array(docs).flatten.map do |doc_path|
|
@@ -321,7 +321,7 @@ module Google
|
|
321
321
|
|
322
322
|
doc_path = coalesce_doc_path_argument doc
|
323
323
|
|
324
|
-
@writes << Convert.
|
324
|
+
@writes << Convert.write_for_create(doc_path, data)
|
325
325
|
|
326
326
|
nil
|
327
327
|
end
|
@@ -422,7 +422,7 @@ module Google
|
|
422
422
|
|
423
423
|
doc_path = coalesce_doc_path_argument doc
|
424
424
|
|
425
|
-
@writes << Convert.
|
425
|
+
@writes << Convert.write_for_set(doc_path, data, merge: merge)
|
426
426
|
|
427
427
|
nil
|
428
428
|
end
|
@@ -526,8 +526,8 @@ module Google
|
|
526
526
|
|
527
527
|
doc_path = coalesce_doc_path_argument doc
|
528
528
|
|
529
|
-
@writes << Convert.
|
530
|
-
|
529
|
+
@writes << Convert.write_for_update(doc_path, data,
|
530
|
+
update_time: update_time)
|
531
531
|
|
532
532
|
nil
|
533
533
|
end
|