google-cloud-firestore 2.4.0 → 2.6.1
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/AUTHENTICATION.md +2 -1
- data/CHANGELOG.md +35 -0
- data/CONTRIBUTING.md +4 -5
- data/LOGGING.md +1 -1
- data/lib/google/cloud/firestore/batch.rb +3 -4
- data/lib/google/cloud/firestore/client.rb +17 -23
- data/lib/google/cloud/firestore/collection_group.rb +136 -0
- data/lib/google/cloud/firestore/collection_reference.rb +9 -6
- 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_reference.rb +9 -2
- data/lib/google/cloud/firestore/document_reference/list.rb +5 -6
- data/lib/google/cloud/firestore/field_path.rb +2 -2
- data/lib/google/cloud/firestore/field_value.rb +7 -2
- data/lib/google/cloud/firestore/query.rb +88 -19
- data/lib/google/cloud/firestore/query_partition.rb +80 -0
- data/lib/google/cloud/firestore/resource_path.rb +58 -0
- data/lib/google/cloud/firestore/service.rb +18 -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 +3 -4
- metadata +9 -6
@@ -18,6 +18,7 @@ require "google/cloud/firestore/document_snapshot"
|
|
18
18
|
require "google/cloud/firestore/collection_reference"
|
19
19
|
require "google/cloud/firestore/document_listener"
|
20
20
|
require "google/cloud/firestore/document_reference/list"
|
21
|
+
require "google/cloud/firestore/resource_path"
|
21
22
|
|
22
23
|
module Google
|
23
24
|
module Cloud
|
@@ -90,11 +91,11 @@ module Google
|
|
90
91
|
# puts col.collection_id
|
91
92
|
# end
|
92
93
|
#
|
93
|
-
def cols
|
94
|
+
def cols &block
|
94
95
|
ensure_service!
|
95
96
|
grpc = service.list_collections path
|
96
97
|
cols_enum = CollectionReferenceList.from_grpc(grpc, client, path).all
|
97
|
-
cols_enum.each
|
98
|
+
cols_enum.each(&block) if block_given?
|
98
99
|
cols_enum
|
99
100
|
end
|
100
101
|
alias collections cols
|
@@ -459,6 +460,12 @@ module Google
|
|
459
460
|
|
460
461
|
# @!endgroup
|
461
462
|
|
463
|
+
# @private
|
464
|
+
def <=> other
|
465
|
+
return nil unless other.is_a? self.class
|
466
|
+
ResourcePath.from_path(path) <=> ResourcePath.from_path(other.path)
|
467
|
+
end
|
468
|
+
|
462
469
|
##
|
463
470
|
# @private New DocumentReference object from a path.
|
464
471
|
def self.from_path path, client
|
@@ -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
|
|
@@ -110,7 +109,7 @@ module Google
|
|
110
109
|
#
|
111
110
|
# @return [Enumerator]
|
112
111
|
#
|
113
|
-
# @example Iterating each document reference by passing a block:
|
112
|
+
# @example Iterating each document reference by passing a block or proc:
|
114
113
|
# require "google/cloud/firestore"
|
115
114
|
#
|
116
115
|
# firestore = Google::Cloud::Firestore.new
|
@@ -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
|
@@ -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
|
|
@@ -27,9 +27,14 @@ module Google
|
|
27
27
|
#
|
28
28
|
# firestore = Google::Cloud::Firestore.new
|
29
29
|
#
|
30
|
-
#
|
30
|
+
# # Get a document reference
|
31
|
+
# nyc_ref = firestore.doc "cities/NYC"
|
31
32
|
#
|
32
|
-
# #
|
33
|
+
# # Set the population to increment by 1.
|
34
|
+
# increment_value = Google::Cloud::Firestore::FieldValue.increment 1
|
35
|
+
#
|
36
|
+
# nyc_ref.update({ name: "New York City",
|
37
|
+
# population: increment_value })
|
33
38
|
#
|
34
39
|
class FieldValue
|
35
40
|
##
|
@@ -17,6 +17,7 @@ require "google/cloud/firestore/v1"
|
|
17
17
|
require "google/cloud/firestore/document_snapshot"
|
18
18
|
require "google/cloud/firestore/query_listener"
|
19
19
|
require "google/cloud/firestore/convert"
|
20
|
+
require "json"
|
20
21
|
|
21
22
|
module Google
|
22
23
|
module Cloud
|
@@ -74,6 +75,16 @@ module Google
|
|
74
75
|
# @private The firestore client object.
|
75
76
|
attr_accessor :client
|
76
77
|
|
78
|
+
##
|
79
|
+
# @private Creates a new Query.
|
80
|
+
def initialize query, parent_path, client, limit_type: nil
|
81
|
+
query ||= StructuredQuery.new
|
82
|
+
@query = query
|
83
|
+
@parent_path = parent_path
|
84
|
+
@limit_type = limit_type
|
85
|
+
@client = client
|
86
|
+
end
|
87
|
+
|
77
88
|
##
|
78
89
|
# Restricts documents matching the query to return only data for the
|
79
90
|
# provided fields.
|
@@ -962,16 +973,71 @@ module Google
|
|
962
973
|
end
|
963
974
|
alias on_snapshot listen
|
964
975
|
|
976
|
+
##
|
977
|
+
# Serializes the instance to a JSON text string. See also {Query.from_json}.
|
978
|
+
#
|
979
|
+
# @return [String] A JSON text string.
|
980
|
+
#
|
981
|
+
# @example
|
982
|
+
# require "google/cloud/firestore"
|
983
|
+
#
|
984
|
+
# firestore = Google::Cloud::Firestore.new
|
985
|
+
# query = firestore.col(:cities).select(:population)
|
986
|
+
#
|
987
|
+
# json = query.to_json
|
988
|
+
#
|
989
|
+
# new_query = Google::Cloud::Firestore::Query.from_json json, firestore
|
990
|
+
#
|
991
|
+
# new_query.get do |city|
|
992
|
+
# puts "#{city.document_id} has #{city[:population]} residents."
|
993
|
+
# end
|
994
|
+
#
|
995
|
+
def to_json options = nil
|
996
|
+
query_json = Google::Cloud::Firestore::V1::StructuredQuery.encode_json query
|
997
|
+
{
|
998
|
+
"query" => JSON.parse(query_json),
|
999
|
+
"parent_path" => parent_path,
|
1000
|
+
"limit_type" => limit_type
|
1001
|
+
}.to_json options
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
##
|
1005
|
+
# Deserializes a JSON text string serialized from this class and returns it as a new instance. See also
|
1006
|
+
# {#to_json}.
|
1007
|
+
#
|
1008
|
+
# @param [String] json A JSON text string serialized using {#to_json}.
|
1009
|
+
# @param [Google::Cloud::Firestore::Client] client A connected client instance.
|
1010
|
+
#
|
1011
|
+
# @return [Query] A new query equal to the original query used to create the JSON text string.
|
1012
|
+
#
|
1013
|
+
# @example
|
1014
|
+
# require "google/cloud/firestore"
|
1015
|
+
#
|
1016
|
+
# firestore = Google::Cloud::Firestore.new
|
1017
|
+
# query = firestore.col(:cities).select(:population)
|
1018
|
+
#
|
1019
|
+
# json = query.to_json
|
1020
|
+
#
|
1021
|
+
# new_query = Google::Cloud::Firestore::Query.from_json json, firestore
|
1022
|
+
#
|
1023
|
+
# new_query.get do |city|
|
1024
|
+
# puts "#{city.document_id} has #{city[:population]} residents."
|
1025
|
+
# end
|
1026
|
+
#
|
1027
|
+
def self.from_json json, client
|
1028
|
+
raise ArgumentError, "client is required" unless client
|
1029
|
+
|
1030
|
+
json = JSON.parse json
|
1031
|
+
query_json = json["query"]
|
1032
|
+
raise ArgumentError, "Field 'query' is required" unless query_json
|
1033
|
+
query = Google::Cloud::Firestore::V1::StructuredQuery.decode_json query_json.to_json
|
1034
|
+
start query, json["parent_path"], client, limit_type: json["limit_type"]&.to_sym
|
1035
|
+
end
|
1036
|
+
|
965
1037
|
##
|
966
1038
|
# @private Start a new Query.
|
967
1039
|
def self.start query, parent_path, client, limit_type: nil
|
968
|
-
query
|
969
|
-
Query.new.tap do |q|
|
970
|
-
q.instance_variable_set :@query, query
|
971
|
-
q.instance_variable_set :@parent_path, parent_path
|
972
|
-
q.instance_variable_set :@limit_type, limit_type
|
973
|
-
q.instance_variable_set :@client, client
|
974
|
-
end
|
1040
|
+
new query, parent_path, client, limit_type: limit_type
|
975
1041
|
end
|
976
1042
|
|
977
1043
|
protected
|
@@ -1010,11 +1076,11 @@ module Google
|
|
1010
1076
|
}.freeze
|
1011
1077
|
##
|
1012
1078
|
# @private
|
1013
|
-
INEQUALITY_FILTERS =
|
1014
|
-
LESS_THAN
|
1015
|
-
LESS_THAN_OR_EQUAL
|
1016
|
-
GREATER_THAN
|
1017
|
-
GREATER_THAN_OR_EQUAL
|
1079
|
+
INEQUALITY_FILTERS = [
|
1080
|
+
:LESS_THAN,
|
1081
|
+
:LESS_THAN_OR_EQUAL,
|
1082
|
+
:GREATER_THAN,
|
1083
|
+
:GREATER_THAN_OR_EQUAL
|
1018
1084
|
].freeze
|
1019
1085
|
|
1020
1086
|
def value_nil? value
|
@@ -1031,15 +1097,16 @@ module Google
|
|
1031
1097
|
value_nil?(value) || value_nan?(value)
|
1032
1098
|
end
|
1033
1099
|
|
1034
|
-
def filter name,
|
1100
|
+
def filter name, op_key, value
|
1035
1101
|
field = StructuredQuery::FieldReference.new field_path: name.to_s
|
1036
|
-
operator = FILTER_OPS[
|
1037
|
-
raise ArgumentError, "unknown operator #{
|
1102
|
+
operator = FILTER_OPS[op_key.to_s.downcase]
|
1103
|
+
raise ArgumentError, "unknown operator #{op_key}" if operator.nil?
|
1038
1104
|
|
1039
1105
|
if value_unary? value
|
1040
|
-
operator =
|
1106
|
+
operator = case operator
|
1107
|
+
when :EQUAL
|
1041
1108
|
value_nan?(value) ? :IS_NAN : :IS_NULL
|
1042
|
-
|
1109
|
+
when :NOT_EQUAL
|
1043
1110
|
value_nan?(value) ? :IS_NOT_NAN : :IS_NOT_NULL
|
1044
1111
|
else
|
1045
1112
|
raise ArgumentError, "can only perform '==' and '!=' comparisons on #{value} values"
|
@@ -1093,11 +1160,14 @@ module Google
|
|
1093
1160
|
return snapshot_to_cursor values.first, query
|
1094
1161
|
end
|
1095
1162
|
|
1163
|
+
# The *values param in start_at, start_after, etc. will wrap an array argument in an array, so unwrap it here.
|
1164
|
+
values = values.first if values.count == 1 && values.first.is_a?(Array)
|
1165
|
+
|
1096
1166
|
# pair values with their field_paths to ensure correct formatting
|
1097
1167
|
order_field_paths = order_by_field_paths query
|
1098
1168
|
if values.count > order_field_paths.count
|
1099
1169
|
# raise if too many values provided for the cursor
|
1100
|
-
raise ArgumentError, "
|
1170
|
+
raise ArgumentError, "There cannot be more cursor values than order by fields"
|
1101
1171
|
end
|
1102
1172
|
|
1103
1173
|
values = values.zip(order_field_paths).map do |value, field_path|
|
@@ -1129,7 +1199,6 @@ module Google
|
|
1129
1199
|
snapshot[field_path]
|
1130
1200
|
end
|
1131
1201
|
end
|
1132
|
-
|
1133
1202
|
values_to_cursor values, query
|
1134
1203
|
end
|
1135
1204
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Copyright 2021 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
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Firestore
|
19
|
+
##
|
20
|
+
# # QueryPartition
|
21
|
+
#
|
22
|
+
# Represents a split point that can be used in a query as a starting and/or end point for the query results.
|
23
|
+
#
|
24
|
+
# The cursors returned by {#start_at} and {#end_before} can only be used in a query that matches the constraint of
|
25
|
+
# the query that produced this partition.
|
26
|
+
#
|
27
|
+
# See {CollectionGroup#partitions} and {Query}.
|
28
|
+
#
|
29
|
+
# @!attribute [r] start_at
|
30
|
+
# The cursor values that define the first result for this partition, or `nil` if this is the first partition.
|
31
|
+
# Returns an array of values that represent a position, in the order they appear in the order by clause of the
|
32
|
+
# query. Can contain fewer values than specified in the order by clause. Will be used in the query returned by
|
33
|
+
# {#to_query}.
|
34
|
+
# @return [Array<Object>, nil] Typically, the values are {DocumentReference} objects.
|
35
|
+
# @!attribute [r] end_before
|
36
|
+
# The cursor values that define the first result after this partition, or `nil` if this is the last partition.
|
37
|
+
# Returns an array of values that represent a position, in the order they appear in the order by clause of the
|
38
|
+
# query. Can contain fewer values than specified in the order by clause. Will be used in the query returned by
|
39
|
+
# {#to_query}.
|
40
|
+
# @return [Array<Object>, nil] Typically, the values are {DocumentReference} objects.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# require "google/cloud/firestore"
|
44
|
+
#
|
45
|
+
# firestore = Google::Cloud::Firestore.new
|
46
|
+
#
|
47
|
+
# col_group = firestore.col_group "cities"
|
48
|
+
#
|
49
|
+
# partitions = col_group.partitions 3
|
50
|
+
#
|
51
|
+
# queries = partitions.map(&:to_query)
|
52
|
+
#
|
53
|
+
class QueryPartition
|
54
|
+
attr_reader :start_at
|
55
|
+
attr_reader :end_before
|
56
|
+
|
57
|
+
##
|
58
|
+
# @private New QueryPartition from query and Cursor
|
59
|
+
def initialize query, start_at, end_before
|
60
|
+
@query = query
|
61
|
+
@start_at = start_at
|
62
|
+
@end_before = end_before
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Creates a new query that only returns the documents for this partition, using the cursor values from
|
67
|
+
# {#start_at} and {#end_before}.
|
68
|
+
#
|
69
|
+
# @return [Query] The query for the partition.
|
70
|
+
#
|
71
|
+
def to_query
|
72
|
+
base_query = @query
|
73
|
+
base_query = base_query.start_at start_at if start_at
|
74
|
+
base_query = base_query.end_before end_before if end_before
|
75
|
+
base_query
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright 2021 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
|
+
module Google
|
17
|
+
module Cloud
|
18
|
+
module Firestore
|
19
|
+
##
|
20
|
+
# @private
|
21
|
+
#
|
22
|
+
# Represents a resource path to the Firestore API.
|
23
|
+
#
|
24
|
+
class ResourcePath
|
25
|
+
include Comparable
|
26
|
+
|
27
|
+
RESOURCE_PATH_RE = %r{^projects/([^/]*)/databases/([^/]*)(?:/documents/)?([\s\S]*)$}.freeze
|
28
|
+
|
29
|
+
attr_reader :project_id
|
30
|
+
attr_reader :database_id
|
31
|
+
attr_reader :segments
|
32
|
+
|
33
|
+
##
|
34
|
+
# Creates a resource path object.
|
35
|
+
#
|
36
|
+
# @param [Array<String>] segments One or more strings representing the resource path.
|
37
|
+
#
|
38
|
+
# @return [ResourcePath] The resource path object.
|
39
|
+
#
|
40
|
+
def initialize project_id, database_id, segments
|
41
|
+
@project_id = project_id
|
42
|
+
@database_id = database_id
|
43
|
+
@segments = segments.split "/"
|
44
|
+
end
|
45
|
+
|
46
|
+
def <=> other
|
47
|
+
return nil unless other.is_a? ResourcePath
|
48
|
+
[project_id, database_id, segments] <=> [other.project_id, other.database_id, other.segments]
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.from_path path
|
52
|
+
data = RESOURCE_PATH_RE.match path
|
53
|
+
new data[1], data[2], data[3]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
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.
|
@@ -93,6 +96,20 @@ module Google
|
|
93
96
|
)
|
94
97
|
end
|
95
98
|
|
99
|
+
##
|
100
|
+
# Returns Google::Cloud::Firestore::V1::PartitionQueryResponse
|
101
|
+
def partition_query parent, query_grpc, partition_count, token: nil, max: nil
|
102
|
+
request = Google::Cloud::Firestore::V1::PartitionQueryRequest.new(
|
103
|
+
parent: parent,
|
104
|
+
structured_query: query_grpc,
|
105
|
+
partition_count: partition_count,
|
106
|
+
page_token: token,
|
107
|
+
page_size: max
|
108
|
+
)
|
109
|
+
paged_enum = firestore.partition_query request
|
110
|
+
paged_enum.response
|
111
|
+
end
|
112
|
+
|
96
113
|
def run_query path, query_grpc, transaction: nil
|
97
114
|
run_query_req = {
|
98
115
|
parent: path,
|