lib/google/cloud/firestore/document_snapshot.rb in google-cloud-firestore-0.22.0 vs lib/google/cloud/firestore/document_snapshot.rb in google-cloud-firestore-0.23.0
- old
+ new
@@ -15,10 +15,11 @@
require "google/cloud/firestore/v1beta1"
require "google/cloud/firestore/document_reference"
require "google/cloud/firestore/collection_reference"
require "google/cloud/firestore/convert"
+require "google/cloud/firestore/watch/order"
module Google
module Cloud
module Firestore
##
@@ -27,10 +28,13 @@
# A document snapshot object is an immutable representation for a
# document in a Cloud Firestore database.
#
# The snapshot can reference a non-existing document.
#
+ # See {DocumentReference#get}, {DocumentReference#listen},
+ # {Query#get}, {Query#listen}, and {QuerySnapshot#docs}.
+ #
# @example
# require "google/cloud/firestore"
#
# firestore = Google::Cloud::Firestore.new
#
@@ -38,10 +42,26 @@
# nyc_snap = firestore.doc("cities/NYC").get
#
# # Get the document data
# nyc_snap[:population] #=> 1000000
#
+ # @example Listen to a document reference for changes:
+ # require "google/cloud/firestore"
+ #
+ # firestore = Google::Cloud::Firestore.new
+ #
+ # # Get a document reference
+ # nyc_ref = firestore.doc "cities/NYC"
+ #
+ # listener = nyc_ref.listen do |snapshot|
+ # puts "The population of #{snapshot[:name]} "
+ # puts "is #{snapshot[:population]}."
+ # end
+ #
+ # # When ready, stop the listen operation and close the stream.
+ # listener.stop
+ #
class DocumentSnapshot
##
# @private The Google::Firestore::V1beta1::Document object.
attr_accessor :grpc
@@ -116,13 +136,15 @@
# @!endgroup
# @!group Data
##
- # Retrieves the document data.
+ # Retrieves the document data. When the document exists the data hash is
+ # frozen and will not allow any changes. When the document does not
+ # exist `nil` will be returned.
#
- # @return [Hash] The document data.
+ # @return [Hash, nil] The document data.
#
# @example
# require "google/cloud/firestore"
#
# firestore = Google::Cloud::Firestore.new
@@ -132,11 +154,11 @@
# # Get the document data
# nyc_snap.data[:population] #=> 1000000
#
def data
return nil if missing?
- Convert.fields_to_hash grpc.fields, ref.client
+ @data ||= Convert.fields_to_hash(grpc.fields, ref.client).freeze
end
alias fields data
##
# Retrieves the document data.
@@ -190,12 +212,13 @@
unless field_path.is_a? FieldPath
field_path = FieldPath.parse field_path
end
nodes = field_path.fields.map(&:to_sym)
- selected_data = data
+ return ref if nodes == [:__name__]
+ selected_data = data
nodes.each do |node|
unless selected_data.is_a? Hash
err_msg = "#{field_path.formatted_string} is not " \
"contained in the data"
raise ArgumentError, err_msg
@@ -284,14 +307,49 @@
def missing?
grpc.nil?
end
##
+ # @private
+ def <=> other
+ return nil unless other.is_a? DocumentSnapshot
+ return data <=> other.data if path == other.path
+ path <=> other.path
+ end
+
+ ##
+ # @private
+ def eql? other
+ return nil unless other.is_a? DocumentSnapshot
+ return data.eql? other.data if path == other.path
+ path.eql? other.path
+ end
+
+ ##
+ # @private
+ def hash
+ @hash ||= [path, data].hash
+ end
+
+ ##
+ # @private
+ def query_comparisons_for query_grpc
+ @memoized_comps ||= {}
+ if @memoized_comps.key? query_grpc.hash
+ return @memoized_comps[query_grpc.hash]
+ end
+
+ @memoized_comps[query_grpc.hash] = query_grpc.order_by.map do |order|
+ Watch::Order.field_comparison get(order.field.field_path)
+ end
+ end
+
+ ##
# @private New DocumentSnapshot from a
# Google::Firestore::V1beta1::RunQueryResponse object.
- def self.from_query_result result, context
- ref = DocumentReference.from_path result.document.name, context
+ def self.from_query_result result, client
+ ref = DocumentReference.from_path result.document.name, client
read_at = Convert.timestamp_to_time result.read_time
new.tap do |s|
s.grpc = result.document
s.instance_variable_set :@ref, ref
@@ -299,24 +357,48 @@
end
end
##
# @private New DocumentSnapshot from a
+ # Google::Firestore::V1beta1::DocumentChange object.
+ def self.from_document document, client, read_at: nil
+ ref = DocumentReference.from_path document.name, client
+
+ new.tap do |s|
+ s.grpc = document
+ s.instance_variable_set :@ref, ref
+ s.instance_variable_set :@read_at, read_at
+ end
+ end
+
+ ##
+ # @private New DocumentSnapshot from a
# Google::Firestore::V1beta1::BatchGetDocumentsResponse object.
- def self.from_batch_result result, context
+ def self.from_batch_result result, client
ref = nil
grpc = nil
if result.result == :found
grpc = result.found
- ref = DocumentReference.from_path grpc.name, context
+ ref = DocumentReference.from_path grpc.name, client
else
- ref = DocumentReference.from_path result.missing, context
+ ref = DocumentReference.from_path result.missing, client
end
read_at = Convert.timestamp_to_time result.read_time
new.tap do |s|
s.grpc = grpc
s.instance_variable_set :@ref, ref
+ s.instance_variable_set :@read_at, read_at
+ end
+ end
+
+ ##
+ # @private New non-existant DocumentSnapshot from a
+ # DocumentReference object.
+ def self.missing doc_ref, read_at: nil
+ new.tap do |s|
+ s.grpc = nil
+ s.instance_variable_set :@ref, doc_ref
s.instance_variable_set :@read_at, read_at
end
end
end
end