aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/include/firebase/firestore/document_reference.h
blob: 9385ed3fc502285b5e37b713f0855b3850cfbc4f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
/*
 * Copyright 2018 Google
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// TODO(rsgowman): This file isn't intended to be used just yet. It's just an
// outline of what the API might eventually look like. Most of this was
// shamelessly stolen and modified from RTDB's header file, melded with the
// (java) firestore api.

#ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_DOCUMENT_REFERENCE_H_
#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_DOCUMENT_REFERENCE_H_

#include <string>
#include <unordered_map>

#if defined(FIREBASE_USE_STD_FUNCTION)
#include <functional>
#endif

#include "firebase/app.h"
#include "firebase/firestore/collection_reference.h"
#include "firebase/firestore/document_snapshot.h"
#include "firebase/firestore/event_listener.h"
#include "firebase/firestore/field_value.h"
#include "firebase/firestore/firestore.h"
#include "firebase/firestore/firestore_errors.h"
#include "firebase/firestore/listener_registration.h"
#include "firebase/firestore/set_options.h"
#include "firebase/future.h"

// TODO(rsgowman): Note that RTDB uses:
//   #if defined(FIREBASE_USE_MOVE_OPERATORS) || defined(DOXYGEN
// to protect move operators from older compilers. But all our supported
// compilers support this, so we've skipped the #if guard. This TODO comment is
// here so we don't forget to mention this during the API review, and should be
// removed once this note has migrated to the API review doc.

namespace firebase {
namespace firestore {

class DocumentReferenceInternal;
class Firestore;
class FirestoreInternal;

// TODO(rsgowman): move this into the FieldValue header
#ifdef STLPORT
using MapFieldValue = std::tr1::unordered_map<std::string, FieldValue>;
#else
using MapFieldValue = std::unordered_map<std::string, FieldValue>;
#endif

/**
 * A DocumentReference refers to a document location in a Firestore database and
 * can be used to write, read, or listen to the location. There may or may not
 * exist a document at the referenced location. A DocumentReference can also be
 * used to create a CollectionReference to a subcollection.
 *
 * Create a DocumentReference via Firebase::Document(const string& path).
 *
 * NOT thread-safe: an instance should not be used from multiple threads
 *
 * Subclassing Note: Firestore classes are not meant to be subclassed except for
 * use in test mocks. Subclassing is not supported in production code and new
 * SDK releases may break code that does so.
 */
class DocumentReference {
 public:
  enum class MetadataChanges {
    kExclude,
    kInclude,
  };

  /**
   * @brief Default constructor. This creates an invalid DocumentReference.
   * Attempting to perform any operations on this reference will fail (and cause
   * a crash) unless a valid DocumentReference has been assigned to it.
   */
  DocumentReference();

  /**
   * @brief Copy constructor. It's totally okay (and efficient) to copy
   * DocumentReference instances, as they simply point to the same location in
   * the database.
   *
   * @param[in] reference DocumentReference to copy from.
   */
  DocumentReference(const DocumentReference& reference);

  /**
   * @brief Move constructor. Moving is an efficient operation for
   * DocumentReference instances.
   *
   * @param[in] reference DocumentReference to move data from.
   */
  DocumentReference(DocumentReference&& reference);

  virtual ~DocumentReference();

  /**
   * @brief Copy assignment operator. It's totally okay (and efficient) to copy
   * DocumentReference instances, as they simply point to the same location in
   * the database.
   *
   * @param[in] reference DocumentReference to copy from.
   *
   * @returns Reference to the destination DocumentReference.
   */
  DocumentReference& operator=(const DocumentReference& reference);

  /**
   * @brief Move assignment operator. Moving is an efficient operation for
   * DocumentReference instances.
   *
   * @param[in] reference DocumentReference to move data from.
   *
   * @returns Reference to the destination DocumentReference.
   */
  DocumentReference& operator=(DocumentReference&& reference);

  /**
   * @brief Returns the Firestore instance associated with this document
   * reference.
   *
   * The pointer will remain valid indefinitely.
   *
   * @returns Firebase Firestore instance that this DocumentReference refers to.
   */
  virtual const Firestore* firestore() const;

  /**
   * @brief Returns the Firestore instance associated with this document
   * reference.
   *
   * The pointer will remain valid indefinitely.
   *
   * @returns Firebase Firestore instance that this DocumentReference refers to.
   */
  virtual Firestore* firestore();

  /**
   * @brief Returns the string id of this document location.
   *
   * The pointer is only valid while the DocumentReference remains in memory.
   *
   * @returns String id of this document location, which will remain valid in
   * memory until the DocumentReference itself goes away.
   */
  virtual const char* id() const;

  /**
   * @brief Returns the string id of this document location.
   *
   * @returns String id of this document location.
   */
  virtual std::string id_string() const;

  /**
   * @brief Returns the path of this document (relative to the root of the
   * database) as a slash-separated string.
   *
   * The pointer is only valid while the DocumentReference remains in memory.
   *
   * @returns String path of this document location, which will remain valid in
   * memory until the DocumentReference itself goes away.
   */
  virtual const char* path() const;

  /**
   * @brief Returns the path of this document (relative to the root of the
   * database) as a slash-separated string.
   *
   * @returns String path of this document location.
   */
  virtual std::string path_string() const;

  /**
   * @brief Returns a CollectionReference to the collection that contains this
   * document.
   */
  virtual CollectionReference get_parent() const;

  /**
   * @brief Returns a CollectionReference instance that refers to the
   * subcollection at the specified path relative to this document.
   *
   * @param[in] collection_path A slash-separated relative path to a
   * subcollection. The pointer only needs to be valid during this call.
   *
   * @return The CollectionReference instance.
   */
  virtual CollectionReference Collection(const char* collection_path) const;

  /**
   * @brief Returns a CollectionReference instance that refers to the
   * subcollection at the specified path relative to this document.
   *
   * @param[in] collection_path A slash-separated relative path to a
   * subcollection.
   *
   * @return The CollectionReference instance.
   */
  virtual CollectionReference Collection(
      const std::string& collection_path) const;

  /**
   * @brief Reads the document referenced by this DocumentReference.
   *
   * @return A Future that will be resolved with the contents of the Document at
   * this DocumentReference.
   */
  virtual Future<DocumentSnapshot> Get() const;

  /**
   * @brief Writes to the document referred to by this DocumentReference.
   *
   * If the document does not yet exist, it will be created. If you pass
   * SetOptions, the provided data can be merged into an existing document.
   *
   * @param[in] data A map of the fields and values for the document.
   * @param[in] options An object to configure the set behavior.
   *
   * @return A Future that will be resolved when the write finishes.
   */
  virtual Future<void> Set(const MapFieldValue& data,
                           const SetOptions& options = SetOptions());

  /**
   * @brief Updates fields in the document referred to by this
   * DocumentReference.
   *
   * If no document exists yet, the update will fail.
   *
   * @param[in] data A map of field / value pairs to update. Fields can contain
   * dots to reference nested fields within the document.
   *
   * @return A Future that will be resolved when the write finishes.
   */
  virtual Future<void> Update(const MapFieldValue& data);

  /**
   * @brief Removes the document referred to by this DocumentReference.
   *
   * @return A Task that will be resolved when the delete completes.
   */
  virtual Future<void> Delete();

  /**
   * @brief Starts listening to the document referenced by this
   * DocumentReference.
   *
   * @param[in] listener The event listener that will be called with the
   * snapshots, which must remain in memory until you remove the listener from
   * this DocumentReference. (Ownership is not transferred; you are responsible
   * for making sure that listener is valid as long as this DocumentReference is
   * valid and the listener is registered.)
   * @param[in] metadata_changes Indicates whether metadata-only changes (i.e.
   * only DocumentSnapshot.getMetadata() changed) should trigger snapshot
   * events.
   *
   * @return A registration object that can be used to remove the listener.
   */
  virtual ListenerRegistration AddSnapshotListener(
      EventListener<DocumentSnapshot>* listener,
      MetadataChanges metadata_changes = MetadataChanges::kExclude);

#if defined(FIREBASE_USE_STD_FUNCTION) || defined(DOXYGEN)
  /**
   * @brief Starts listening to the document referenced by this
   * DocumentReference.
   *
   * @param[in] callback function or lambda to call. When this function is
   * called, exactly one of the parameters will be non-null.
   * @param[in] metadata_changes Indicates whether metadata-only changes (i.e.
   * only DocumentSnapshot.getMetadata() changed) should trigger snapshot
   * events.
   *
   * @return A registration object that can be used to remove the listener.
   *
   * @note This method is not available when using STLPort on Android, as
   * std::function is not supported on STLPort.
   */
  virtual ListenerRegistration AddSnapshotListener(
      std::function<void(const DocumentSnapshot*, const Error*)> callback,
      MetadataChanges metadata_changes = MetadataChanges::kExclude);
#endif  // defined(FIREBASE_USE_STD_FUNCTION) || defined(DOXYGEN)

 protected:
  explicit DocumentReference(DocumentReferenceInternal* internal);

 private:
  friend class FirestoreInternal;

  // TODO(zxu123): investigate possibility to use std::unique_ptr or
  // firebase::UniquePtr.
  DocumentReferenceInternal* internal_ = nullptr;
};

bool operator==(const DocumentReference& lhs, const DocumentReference& rhs);

inline bool operator!=(const DocumentReference& lhs,
                       const DocumentReference& rhs) {
  return !(lhs == rhs);
}

// TODO(rsgowman): probably define and inline here.
bool operator<(const DocumentReference& lhs, const DocumentReference& rhs);

inline bool operator>(const DocumentReference& lhs,
                      const DocumentReference& rhs) {
  return rhs < lhs;
}

inline bool operator<=(const DocumentReference& lhs,
                       const DocumentReference& rhs) {
  return !(lhs > rhs);
}

inline bool operator>=(const DocumentReference& lhs,
                       const DocumentReference& rhs) {
  return !(lhs < rhs);
}

}  // namespace firestore
}  // namespace firebase

namespace std {
// TODO(rsgowman): NB that specialization of std::hash deviates from the Google
// C++ style guide. But we think this is probably ok in this case since:
// a) It's the standard way of doing this outside of Google (as the style guide
// itself points out), and
// b) This has a straightforward hash function anyway (just hash the path) so I
// don't think the concerns in the style guide are going to bite us.
//
// Raise this concern during the API review.
template <>
struct hash<firebase::firestore::DocumentReference> {
  std::size_t operator()(
      const firebase::firestore::DocumentReference& doc_ref) const;
};
}  // namespace std

#endif  // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_DOCUMENT_REFERENCE_H_