This commit is contained in:
Yao
2024-12-20 17:49:45 +08:00
parent 86b0363ce1
commit 654d456c7d
7011 changed files with 1705926 additions and 7 deletions

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRAggregateField.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRAggregateQuery.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRAggregateQuerySnapshot.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRAggregateSource.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRCollectionReference.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRDocumentChange.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRDocumentReference.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRDocumentSnapshot.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRFieldPath.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRFieldValue.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRFilter.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRFirestore.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRFirestoreErrors.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRFirestoreSettings.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRFirestoreSource.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRGeoPoint.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRListenerRegistration.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRLoadBundleTask.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRLocalCacheSettings.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRPersistentCacheIndexManager.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRQuery.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRQuerySnapshot.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2024 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRSnapshotListenOptions.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRSnapshotMetadata.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRTimestamp.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRTransaction.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRTransactionOptions.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FIRWriteBatch.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
#import <FirebaseFirestoreInternal/FirebaseFirestore.h>

View File

@@ -0,0 +1,15 @@
// Copyright 2023 Google LLC
//
// 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.
// Swift Package Manager needs at least one source file.

445
Pods/FirebaseFirestore/Firestore/LICENSE generated Normal file
View File

@@ -0,0 +1,445 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
--------------------------
nlohmann_json
--------------------------
MIT License
Copyright (c) 2013-2020 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
--------------------------
FirestoreEncoder
--------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
## Runtime Library Exception to the Apache 2.0 License: ##
As an exception, if you use this Software to compile your source code and
portions of this Software are embedded into the binary product as a result,
you may redistribute such product without providing attribution as would
otherwise be required by Sections 4(a), 4(b) and 4(d) of the License.

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2021 Google LLC
*
* 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
import Foundation
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
public extension CollectionReference {
/// Adds a new document to this collection with the specified data, assigning it a document ID
/// automatically.
/// - Parameter data: A `Dictionary` containing the data for the new document.
/// - Throws: `Error` if the backend rejected the write.
/// - Returns: A `DocumentReference` pointing to the newly created document.
@discardableResult
func addDocument(data: [String: Any]) async throws -> DocumentReference {
return try await withCheckedThrowingContinuation { continuation in
var document: DocumentReference?
document = self.addDocument(data: data) { error in
if let err = error {
continuation.resume(throwing: err)
} else {
// Our callbacks guarantee that we either return an error or a document.
continuation.resume(returning: document!)
}
}
}
}
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright 2021 Google LLC
*
* 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
import Foundation
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
public extension Firestore {
/// Loads a Firestore bundle into the local cache.
/// - Parameter bundleData: Data from the bundle to be loaded.
/// - Throws: `Error` if the bundle data cannot be parsed.
/// - Returns: The final `LoadBundleTaskProgress` that contains the total number of documents
/// loaded.
func loadBundle(_ bundleData: Data) async throws -> LoadBundleTaskProgress {
return try await withCheckedThrowingContinuation { continuation in
self.loadBundle(bundleData) { progress, error in
if let err = error {
continuation.resume(throwing: err)
} else {
// Our callbacks guarantee that we either return an error or a progress event.
continuation.resume(returning: progress!)
}
}
}
}
/// Loads a Firestore bundle into the local cache.
/// - Parameter bundleStream: An input stream from which the bundle can be read.
/// - Throws: `Error` if the bundle stream cannot be parsed.
/// - Returns: The final `LoadBundleTaskProgress` that contains the total number of documents
/// loaded.
func loadBundle(_ bundleStream: InputStream) async throws -> LoadBundleTaskProgress {
return try await withCheckedThrowingContinuation { continuation in
self.loadBundle(bundleStream) { progress, error in
if let err = error {
continuation.resume(throwing: err)
} else {
// Our callbacks guarantee that we either return an error or a progress event.
continuation.resume(returning: progress!)
}
}
}
}
/// Executes the given updateBlock and then attempts to commit the changes applied within an
/// atomic
/// transaction.
///
/// The maximum number of writes allowed in a single transaction is 500, but note that each
/// usage of
/// `FieldValue.serverTimestamp()`, `FieldValue.arrayUnion()`, `FieldValue.arrayRemove()`, or
/// `FieldValue.increment()` inside a transaction counts as an additional write.
///
/// In the `updateBlock`, a set of reads and writes can be performed atomically using the
/// `Transaction` object passed to the block. After the `updateBlock` is run, Firestore will
/// attempt
/// to apply the changes to the server. If any of the data read has been modified outside of
/// this
/// transaction since being read, then the transaction will be retried by executing the
/// `updateBlock`
/// again. If the transaction still fails after 5 retries, then the transaction will fail.
///
/// Since the `updateBlock` may be executed multiple times, it should avoiding doing anything
/// that
/// would cause side effects.
///
/// Any value maybe be returned from the `updateBlock`. If the transaction is successfully
/// committed,
/// then the completion block will be passed that value. The `updateBlock` also has an `NSError`
/// out
/// parameter. If this is set, then the transaction will not attempt to commit, and the given
/// error
/// will be returned.
///
/// The `Transaction` object passed to the `updateBlock` contains methods for accessing
/// documents
/// and collections. Unlike other firestore access, data accessed with the transaction will not
/// reflect local changes that have not been committed. For this reason, it is required that all
/// reads are performed before any writes. Transactions must be performed while online.
/// Otherwise,
/// reads will fail, the final commit will fail, and this function will return an error.
///
/// - Parameter updateBlock The block to execute within the transaction context.
/// - Throws Throws an error if the transaction could not be committed, or if an error was
/// explicitly specified in the `updateBlock` parameter.
/// - Returns Returns the value returned in the `updateBlock` parameter if no errors occurred.
func runTransaction(_ updateBlock: @escaping (Transaction, NSErrorPointer)
-> Any?) async throws -> Any? {
// This needs to be wrapped in order to express a nullable return value upon success.
// See https://github.com/firebase/firebase-ios-sdk/issues/9426 for more details.
return try await withCheckedThrowingContinuation { continuation in
self.runTransaction(updateBlock) { anyValue, error in
if let err = error {
continuation.resume(throwing: err)
} else {
continuation.resume(returning: anyValue)
}
}
}
}
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2019 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.
*/
public enum FirestoreDecodingError: Error {
case decodingIsNotSupported(String)
case fieldNameConflict(String)
}
public enum FirestoreEncodingError: Error {
case encodingIsNotSupported(String)
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2019 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.
*/
import FirebaseSharedSwift
import Foundation
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
struct FirestorePassthroughTypes: StructureCodingPassthroughTypeResolver {
static func isPassthroughType<T>(_ t: T) -> Bool {
return
t is GeoPoint ||
t is Timestamp ||
t is FieldValue ||
t is DocumentReference
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2019 Google LLC
*
* 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.
*/
import Foundation
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
public extension CollectionReference {
/// Encodes an instance of `Encodable` and adds a new document to this collection
/// with the encoded data, assigning it a document ID automatically.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - encoder: An encoder instance to use to run the encoding.
/// - completion: A block to execute once the document has been successfully
/// written to the server. This block will not be called while
/// the client is offline, though local changes will be visible
/// immediately.
/// - Returns: A `DocumentReference` pointing to the newly created document.
@discardableResult
func addDocument<T: Encodable>(from value: T,
encoder: Firestore.Encoder = Firestore.Encoder(),
completion: ((Error?) -> Void)? = nil) throws
-> DocumentReference {
let encoded = try encoder.encode(value)
return addDocument(data: encoded, completion: completion)
}
}

View File

@@ -0,0 +1,192 @@
/*
* Copyright 2019 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
@_implementationOnly import FirebaseCoreExtension
import FirebaseSharedSwift
extension CodingUserInfoKey {
static let documentRefUserInfoKey =
CodingUserInfoKey(rawValue: "DocumentRefUserInfoKey")!
}
/// A type that can initialize itself from a Firestore `DocumentReference`,
/// which makes it suitable for use with the `@DocumentID` property wrapper.
///
/// Firestore includes extensions that make `String` and `DocumentReference`
/// conform to `DocumentIDWrappable`.
///
/// Note that Firestore ignores fields annotated with `@DocumentID` when writing
/// so there is no requirement to convert from the wrapped type back to a
/// `DocumentReference`.
public protocol DocumentIDWrappable {
/// Creates a new instance by converting from the given `DocumentReference`.
static func wrap(_ documentReference: DocumentReference) throws -> Self
}
extension String: DocumentIDWrappable {
public static func wrap(_ documentReference: DocumentReference) throws -> Self {
return documentReference.documentID
}
}
extension DocumentReference: DocumentIDWrappable {
public static func wrap(_ documentReference: DocumentReference) throws -> Self {
// Swift complains that values of type DocumentReference cannot be returned
// as Self which is nonsensical. The cast forces this to work.
return documentReference as! Self
}
}
/// An internal protocol that allows Firestore.Decoder to test if a type is a
/// DocumentID of some kind without knowing the specific generic parameter that
/// the user actually used.
///
/// This is required because Swift does not define an existential type for all
/// instances of a generic class--that is, it has no wildcard or raw type that
/// matches a generic without any specific parameter. Swift does define an
/// existential type for protocols though, so this protocol (to which DocumentID
/// conforms) indirectly makes it possible to test for and act on any
/// `DocumentID<Value>`.
protocol DocumentIDProtocol {
/// Initializes the DocumentID from a DocumentReference.
init(from documentReference: DocumentReference?) throws
}
/// A property wrapper type that marks a `DocumentReference?` or `String?` field to
/// be populated with a document identifier when it is read.
///
/// Apply the `@DocumentID` annotation to a `DocumentReference?` or `String?`
/// property in a `Codable` object to have it populated with the document
/// identifier when it is read and decoded from Firestore.
///
/// - Important: The name of the property annotated with `@DocumentID` must not
/// match the name of any fields in the Firestore document being read or else
/// an error will be thrown. For example, if the `Codable` object has a
/// property named `firstName` annotated with `@DocumentID`, and the Firestore
/// document contains a field named `firstName`, an error will be thrown when
/// attempting to decode the document.
///
/// - Example Read:
/// ````
/// struct Player: Codable {
/// @DocumentID var playerID: String?
/// var health: Int64
/// }
///
/// let p = try! await Firestore.firestore()
/// .collection("players")
/// .document("player-1")
/// .getDocument(as: Player.self)
/// print("\(p.playerID!) Health: \(p.health)")
///
/// // Prints: "Player: player-1, Health: 95"
/// ````
///
/// - Important: Trying to encode/decode this type using encoders/decoders other than
/// Firestore.Encoder throws an error.
///
/// - Important: When writing a Codable object containing an `@DocumentID` annotated field,
/// its value is ignored. This allows you to read a document from one path and
/// write it into another without adjusting the value here.
@propertyWrapper
public struct DocumentID<Value: DocumentIDWrappable & Codable>:
StructureCodingUncodedUnkeyed {
private var value: Value? = nil
public init(wrappedValue value: Value?) {
if let value = value {
logIgnoredValueWarning(value: value)
}
self.value = value
}
public var wrappedValue: Value? {
get { value }
set {
if let someNewValue = newValue {
logIgnoredValueWarning(value: someNewValue)
}
value = newValue
}
}
private func logIgnoredValueWarning(value: Value) {
FirebaseLogger.log(
level: .warning,
service: "[FirebaseFirestoreSwift]",
code: "I-FST000002",
message: """
Attempting to initialize or set a @DocumentID property with a non-nil \
value: "\(value)". The document ID is managed by Firestore and any \
initialized or set value will be ignored. The ID is automatically set \
when reading from Firestore.
"""
)
}
}
extension DocumentID: DocumentIDProtocol {
init(from documentReference: DocumentReference?) throws {
if let documentReference = documentReference {
value = try Value.wrap(documentReference)
} else {
value = nil
}
}
}
extension DocumentID: Codable {
/// A `Codable` object containing an `@DocumentID` annotated field should
/// only be decoded with `Firestore.Decoder`; this initializer throws if an
/// unsupported decoder is used.
///
/// - Parameter decoder: A decoder.
/// - Throws: ``FirestoreDecodingError``
public init(from decoder: Decoder) throws {
guard let reference = decoder
.userInfo[CodingUserInfoKey.documentRefUserInfoKey] as? DocumentReference else {
throw FirestoreDecodingError.decodingIsNotSupported(
"""
Could not find DocumentReference for user info key: \(CodingUserInfoKey
.documentRefUserInfoKey).
DocumentID values can only be decoded with Firestore.Decoder
"""
)
}
try self.init(from: reference)
}
/// A `Codable` object containing an `@DocumentID` annotated field can only
/// be encoded with `Firestore.Encoder`; this initializer always throws.
///
/// - Parameter encoder: An invalid encoder.
/// - Throws: ``FirestoreEncodingError``
public func encode(to encoder: Encoder) throws {
throw FirestoreEncodingError.encodingIsNotSupported(
"DocumentID values can only be encoded with Firestore.Encoder"
)
}
}
extension DocumentID: Equatable where Value: Equatable {}
extension DocumentID: Hashable where Value: Hashable {}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2019 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
/** Mark DocumentReference to conform to Codable. */
/**
* A protocol describing the encodable properties of a DocumentReference.
*
* Note: this protocol exists as a workaround for the Swift compiler: if the DocumentReference class
* was extended directly to conform to Codable, the methods implementing the protocol would be need
* to be marked required but that can't be done in an extension. Declaring the extension on the
* protocol sidesteps this issue.
*/
private protocol CodableDocumentReference: Codable {}
/**
* DocumentReference's codable implmentation will just throw for most
* encoder/decoder however. It is only meant to be encoded by Firestore.Encoder/Firestore.Decoder.
*/
extension CodableDocumentReference {
public init(from decoder: Decoder) throws {
throw FirestoreDecodingError.decodingIsNotSupported(
"DocumentReference values can only be decoded with Firestore.Decoder"
)
}
public func encode(to encoder: Encoder) throws {
throw FirestoreEncodingError.encodingIsNotSupported(
"DocumentReference values can only be encoded with Firestore.Encoder"
)
}
}
extension DocumentReference: CodableDocumentReference {}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2021 Google LLC
*
* 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.
*/
import Foundation
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
public extension DocumentReference {
/// Fetches and decodes the document referenced by this `DocumentReference`.
///
/// This allows users to retrieve a Firestore document and have it decoded to
/// an instance of caller-specified type as follows:
/// ```swift
/// ref.getDocument(as: Book.self) { result in
/// do {
/// let book = try result.get()
/// } catch {
/// // Handle error
/// }
/// }
/// ```
///
/// This method attempts to provide up-to-date data when possible by waiting
/// for data from the server, but it may return cached data or fail if you are
/// offline and the server cannot be reached. If `T` denotes an optional
/// type, the method returns a successful status with a value of `nil` for
/// non-existing documents.
///
/// - Parameters:
/// - as: A `Decodable` type to convert the document fields to.
/// - serverTimestampBehavior: Configures how server timestamps that have
/// not yet been set to their final value are returned from the snapshot.
/// - decoder: The decoder to use to convert the document. Defaults to use
/// the default decoder.
/// - source: Indicates whether the results should be fetched from the cache only
/// (`Source.cache`), the server only (`Source.server`), or to attempt the
/// server and fall back to the cache (`Source.default`).
/// - completion: The closure to call when the document snapshot has been
/// fetched and decoded.
func getDocument<T: Decodable>(as type: T.Type,
with serverTimestampBehavior: ServerTimestampBehavior =
.none,
decoder: Firestore.Decoder = .init(),
source: FirestoreSource = .default,
completion: @escaping (Result<T, Error>) -> Void) {
getDocument(source: source) { snapshot, error in
guard let snapshot = snapshot else {
/**
* Force unwrapping here is fine since this logic corresponds to the auto-synthesized
* async/await wrappers for Objective-C functions with callbacks taking an object and an error
* parameter. The API should (and does) guarantee that either object or error is set, but never both.
* For more details see:
* https://github.com/firebase/firebase-ios-sdk/pull/9101#discussion_r809117034
*/
completion(.failure(error!))
return
}
let result = Result {
try snapshot.data(as: T.self,
with: serverTimestampBehavior,
decoder: decoder)
}
completion(result)
}
}
/// Fetches and decodes the document referenced by this `DocumentReference`.
///
/// This allows users to retrieve a Firestore document and have it decoded
/// to an instance of caller-specified type as follows:
/// ```swift
/// do {
/// let book = try await ref.getDocument(as: Book.self)
/// } catch {
/// // Handle error
/// }
/// ```
///
/// This method attempts to provide up-to-date data when possible by waiting
/// for data from the server, but it may return cached data or fail if you
/// are offline and the server cannot be reached. If `T` denotes
/// an optional type, the method returns a successful status with a value
/// of `nil` for non-existing documents.
///
/// - Parameters:
/// - as: A `Decodable` type to convert the document fields to.
/// - serverTimestampBehavior: Configures how server timestamps that have
/// not yet been set to their final value are returned from the
/// snapshot.
/// - decoder: The decoder to use to convert the document. Defaults to use
/// the default decoder.
/// - source: Indicates whether the results should be fetched from the cache only
/// (`Source.cache`), the server only (`Source.server`), or to attempt the
/// server and fall back to the cache (`Source.default`).
/// - Returns: This instance of the supplied `Decodable` type `T`.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
func getDocument<T: Decodable>(as type: T.Type,
with serverTimestampBehavior: ServerTimestampBehavior =
.none,
decoder: Firestore.Decoder = .init(),
source: FirestoreSource = .default) async throws -> T {
let snapshot = try await getDocument(source: source)
return try snapshot.data(as: T.self,
with: serverTimestampBehavior,
decoder: decoder)
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2019 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.
*/
import Foundation
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
public extension DocumentReference {
/// Encodes an instance of `Encodable` and overwrites the encoded data
/// to the document referred by this `DocumentReference`. If no document exists,
/// it is created. If a document already exists, it is overwritten.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - encoder: An encoder instance to use to run the encoding.
/// - completion: A closure to execute once the document has been successfully
/// written to the server. This closure will not be called while
/// the client is offline, though local changes will be visible
/// immediately.
func setData<T: Encodable>(from value: T,
encoder: Firestore.Encoder = Firestore.Encoder(),
completion: ((Error?) -> Void)? = nil) throws {
let encoded = try encoder.encode(value)
setData(encoded, completion: completion)
}
/// Encodes an instance of `Encodable` and overwrites the encoded data
/// to the document referred by this `DocumentReference`. If no document exists,
/// it is created. If a document already exists, it is overwritten. If you pass
/// merge:true, the provided `Encodable` will be merged into any existing document.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - merge: Whether to merge the provided `Encodable` into any existing
/// document.
/// - encoder: An encoder instance to use to run the encoding.
/// - completion: A closure to execute once the document has been successfully
/// written to the server. This closure will not be called while
/// the client is offline, though local changes will be visible
/// immediately.
func setData<T: Encodable>(from value: T,
merge: Bool,
encoder: Firestore.Encoder = Firestore.Encoder(),
completion: ((Error?) -> Void)? = nil) throws {
let encoded = try encoder.encode(value)
setData(encoded, merge: merge, completion: completion)
}
/// Encodes an instance of `Encodable` and writes the encoded data to the document referred
/// by this `DocumentReference` by only replacing the fields specified under `mergeFields`.
/// Any field that is not specified in mergeFields is ignored and remains untouched. If the
/// document doesnt yet exist, this method creates it and then sets the data.
///
/// It is an error to include a field in `mergeFields` that does not have a corresponding
/// field in the `Encodable`.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - mergeFields: Array of `String` or `FieldPath` elements specifying which fields to
/// merge. Fields can contain dots to reference nested fields within the
/// document.
/// - encoder: An encoder instance to use to run the encoding.
/// - completion: A closure to execute once the document has been successfully
/// written to the server. This closure will not be called while
/// the client is offline, though local changes will be visible
/// immediately.
func setData<T: Encodable>(from value: T,
mergeFields: [Any],
encoder: Firestore.Encoder = Firestore.Encoder(),
completion: ((Error?) -> Void)? = nil) throws {
let encoded = try encoder.encode(value)
setData(encoded, mergeFields: mergeFields, completion: completion)
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2019 Google LLC
*
* 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.
*/
import Foundation
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
public extension DocumentSnapshot {
/// Retrieves all fields in a document and converts them to an instance of
/// caller-specified type.
///
/// By default, server-provided timestamps that have not yet been set to their
/// final value will be returned as `NSNull`. Pass `serverTimestampBehavior`
/// to configure this behavior.
///
/// See `Firestore.Decoder` for more details about the decoding process.
///
/// - Parameters
/// - type: The type to convert the document fields to.
/// - serverTimestampBehavior: Configures how server timestamps that have
/// not yet been set to their final value are returned from the snapshot.
/// - decoder: The decoder to use to convert the document. Defaults to use
/// the default decoder.
func data<T: Decodable>(as type: T.Type,
with serverTimestampBehavior: ServerTimestampBehavior = .none,
decoder: Firestore.Decoder = .init()) throws -> T {
let d: Any = data(with: serverTimestampBehavior) ?? NSNull()
return try decoder.decode(T.self, from: d, in: reference)
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright 2022 Google LLC
*
* 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
import FirebaseSharedSwift
import Foundation
public extension Firestore {
class Encoder {
/// The strategy to use in encoding dates. Defaults to `.timestamp`.
public var dateEncodingStrategy: FirebaseDataEncoder.DateEncodingStrategy = .timestamp
/// Firestore encodes Data as `NSData` blobs versus the default .base64 strings.
public var dataEncodingStrategy: FirebaseDataEncoder.DataEncodingStrategy = .blob
/// The strategy to use in encoding non-conforming numbers. Defaults to `.throw`.
public var nonConformingFloatEncodingStrategy: FirebaseDataEncoder
.NonConformingFloatEncodingStrategy = .throw
/// The strategy to use for encoding keys. Defaults to `.useDefaultKeys`.
public var keyEncodingStrategy: FirebaseDataEncoder.KeyEncodingStrategy = .useDefaultKeys
/// Contextual user-provided information for use during encoding.
public var userInfo: [CodingUserInfoKey: Any] = [:]
public func encode<T: Encodable>(_ value: T) throws -> [String: Any] {
let encoder = FirebaseDataEncoder()
encoder.dateEncodingStrategy = dateEncodingStrategy
encoder.dataEncodingStrategy = dataEncodingStrategy
encoder.nonConformingFloatEncodingStrategy = nonConformingFloatEncodingStrategy
encoder.keyEncodingStrategy = keyEncodingStrategy
encoder.passthroughTypeResolver = FirestorePassthroughTypes.self
encoder.userInfo = userInfo
let encoded = try encoder.encode(value)
guard let dictionaryValue = encoded as? [String: Any] else {
throw EncodingError
.invalidValue(value,
EncodingError
.Context(codingPath: [],
debugDescription: "Top-level \(T.self) is not allowed."))
}
return dictionaryValue
}
public init() {}
}
class Decoder {
/// The strategy to use in decoding dates. Defaults to `.timestamp`.
public var dateDecodingStrategy: FirebaseDataDecoder.DateDecodingStrategy = .timestamp
/// Firestore decodes Data from `NSData` blobs versus the default .base64 strings.
public var dataDecodingStrategy: FirebaseDataDecoder.DataDecodingStrategy = .blob
/// The strategy to use in decoding non-conforming numbers. Defaults to `.throw`.
public var nonConformingFloatDecodingStrategy: FirebaseDataDecoder
.NonConformingFloatDecodingStrategy = .throw
/// The strategy to use for decoding keys. Defaults to `.useDefaultKeys`.
public var keyDecodingStrategy: FirebaseDataDecoder.KeyDecodingStrategy = .useDefaultKeys
/// Contextual user-provided information for use during decoding.
public var userInfo: [CodingUserInfoKey: Any] = [:]
public func decode<T: Decodable>(_ t: T.Type, from data: Any) throws -> T {
let decoder = FirebaseDataDecoder()
decoder.dateDecodingStrategy = dateDecodingStrategy
decoder.dataDecodingStrategy = dataDecodingStrategy
decoder.nonConformingFloatDecodingStrategy = nonConformingFloatDecodingStrategy
decoder.keyDecodingStrategy = keyDecodingStrategy
decoder.passthroughTypeResolver = FirestorePassthroughTypes.self
decoder.userInfo = userInfo
// configure for firestore
return try decoder.decode(t, from: data)
}
public func decode<T: Decodable>(_ t: T.Type, from data: Any,
in reference: DocumentReference?) throws -> T {
if let reference = reference {
userInfo[CodingUserInfoKey.documentRefUserInfoKey] = reference
}
return try decode(T.self, from: data)
}
public init() {}
}
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright 2019 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
/// Wraps an `Optional` field in a `Codable` object such that when the field
/// has a `nil` value it will encode to a null value in Firestore. Normally,
/// optional fields are omitted from the encoded document.
///
/// This is useful for ensuring a field is present in a Firestore document,
/// even when there is no associated value.
@propertyWrapper
public struct ExplicitNull<Value> {
var value: Value?
public init(wrappedValue value: Value?) {
self.value = value
}
public var wrappedValue: Value? {
get { value }
set { value = newValue }
}
}
extension ExplicitNull: Equatable where Value: Equatable {}
extension ExplicitNull: Hashable where Value: Hashable {}
extension ExplicitNull: Encodable where Value: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
if let value = value {
try container.encode(value)
} else {
try container.encodeNil()
}
}
}
extension ExplicitNull: Decodable where Value: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
value = nil
} else {
value = try container.decode(Value.self)
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2019 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
/** Extends FieldValue to conform to Encodable. */
extension FieldValue: Encodable {
/// Encoding a FieldValue will throw by default unless the encoder implementation
/// explicitly handles it, which is what Firestore.Encoder does.
public func encode(to encoder: Encoder) throws {
throw FirestoreEncodingError.encodingIsNotSupported(
"FieldValue values can only be encoded with Firestore.Encoder"
)
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
/**
* A protocol describing the encodable properties of a GeoPoint.
*
* Note: this protocol exists as a workaround for the Swift compiler: if the GeoPoint class
* was extended directly to conform to Codable, the methods implementing the protocol would be need
* to be marked required but that can't be done in an extension. Declaring the extension on the
* protocol sidesteps this issue.
*/
private protocol CodableGeoPoint: Codable {
var latitude: Double { get }
var longitude: Double { get }
init(latitude: Double, longitude: Double)
}
/** The keys in a GeoPoint. Must match the properties of CodableGeoPoint. */
private enum GeoPointKeys: String, CodingKey {
case latitude
case longitude
}
/**
* An extension of GeoPoint that implements the behavior of the Codable protocol.
*
* Note: this is implemented manually here because the Swift compiler can't synthesize these methods
* when declaring an extension to conform to Codable.
*/
extension CodableGeoPoint {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: GeoPointKeys.self)
let latitude = try container.decode(Double.self, forKey: .latitude)
let longitude = try container.decode(Double.self, forKey: .longitude)
self.init(latitude: latitude, longitude: longitude)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: GeoPointKeys.self)
try container.encode(latitude, forKey: .latitude)
try container.encode(longitude, forKey: .longitude)
}
}
/** Extends GeoPoint to conform to Codable. */
extension GeoPoint: CodableGeoPoint {}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2019 Google LLC
*
* 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
/// A type that can initialize itself from a Firestore Timestamp, which makes
/// it suitable for use with the `@ServerTimestamp` property wrapper.
///
/// Firestore includes extensions that make `Timestamp` and `Date` conform to
/// `ServerTimestampWrappable`.
public protocol ServerTimestampWrappable {
/// Creates a new instance by converting from the given `Timestamp`.
///
/// - Parameter timestamp: The timestamp from which to convert.
static func wrap(_ timestamp: Timestamp) throws -> Self
/// Converts this value into a Firestore `Timestamp`.
///
/// - Returns: A `Timestamp` representation of this value.
static func unwrap(_ value: Self) throws -> Timestamp
}
extension Date: ServerTimestampWrappable {
public static func wrap(_ timestamp: Timestamp) throws -> Self {
return timestamp.dateValue()
}
public static func unwrap(_ value: Self) throws -> Timestamp {
return Timestamp(date: value)
}
}
extension Timestamp: ServerTimestampWrappable {
public static func wrap(_ timestamp: Timestamp) throws -> Self {
return timestamp as! Self
}
public static func unwrap(_ value: Timestamp) throws -> Timestamp {
return value
}
}
/// A property wrapper that marks an `Optional<Timestamp>` field to be
/// populated with a server timestamp. If a `Codable` object being written
/// contains a `nil` for an `@ServerTimestamp`-annotated field, it will be
/// replaced with `FieldValue.serverTimestamp()` as it is sent.
///
/// Example:
/// ```
/// struct CustomModel {
/// @ServerTimestamp var ts: Timestamp?
/// }
/// ```
///
/// Then writing `CustomModel(ts: nil)` will tell server to fill `ts` with
/// current timestamp.
@propertyWrapper
public struct ServerTimestamp<Value>: Codable
where Value: ServerTimestampWrappable & Codable {
var value: Value?
public init(wrappedValue value: Value?) {
self.value = value
}
public var wrappedValue: Value? {
get { value }
set { value = newValue }
}
// MARK: Codable
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if container.decodeNil() {
value = nil
} else {
value = try Value.wrap(container.decode(Timestamp.self))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
if let value = value {
try container.encode(Value.unwrap(value))
} else {
try container.encode(FieldValue.serverTimestamp())
}
}
}
extension ServerTimestamp: Equatable where Value: Equatable {}
extension ServerTimestamp: Hashable where Value: Hashable {}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2019 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
/**
* A protocol describing the encodable properties of a Timestamp.
*
* Note: this protocol exists as a workaround for the Swift compiler: if the Timestamp class
* was extended directly to conform to Codable, the methods implementing the protocol would be need
* to be marked required but that can't be done in an extension. Declaring the extension on the
* protocol sidesteps this issue.
*/
private protocol CodableTimestamp: Codable {
var seconds: Int64 { get }
var nanoseconds: Int32 { get }
init(seconds: Int64, nanoseconds: Int32)
}
/** The keys in a Timestamp. Must match the properties of CodableTimestamp. */
private enum TimestampKeys: String, CodingKey {
case seconds
case nanoseconds
}
/**
* An extension of Timestamp that implements the behavior of the Codable protocol.
*
* Note: this is implemented manually here because the Swift compiler can't synthesize these methods
* when declaring an extension to conform to Codable.
*/
extension CodableTimestamp {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: TimestampKeys.self)
let seconds = try container.decode(Int64.self, forKey: .seconds)
let nanoseconds = try container.decode(Int32.self, forKey: .nanoseconds)
self.init(seconds: seconds, nanoseconds: nanoseconds)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: TimestampKeys.self)
try container.encode(seconds, forKey: .seconds)
try container.encode(nanoseconds, forKey: .nanoseconds)
}
}
/** Extends Timestamp to conform to Codable. */
extension Timestamp: CodableTimestamp {}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2022 Google LLC
*
* 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.
*/
import Foundation
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
import FirebaseSharedSwift
public extension FirebaseDataDecoder.DateDecodingStrategy {
/// Decode the `Date` from a Firestore `Timestamp`
static var timestamp: FirebaseDataDecoder.DateDecodingStrategy {
return .custom { decoder in
let container = try decoder.singleValueContainer()
let value = try container.decode(Timestamp.self)
return value.dateValue()
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2022 Google LLC
*
* 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
import FirebaseSharedSwift
import Foundation
public extension FirebaseDataEncoder.DateEncodingStrategy {
/// Encode the `Date` as a Firestore `Timestamp`.
static var timestamp: FirebaseDataEncoder.DateEncodingStrategy {
return .custom { date, encoder in
var container = encoder.singleValueContainer()
try container.encode(Timestamp(date: date))
}
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2019 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.
*/
import Foundation
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
public extension Transaction {
/// Encodes an instance of `Encodable` and overwrites the encoded data
/// to the document referred by `doc`. If no document exists,
/// it is created. If a document already exists, it is overwritten.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: a instance of `Encoded` to be encoded to a document.
/// - encoder: The encoder instance to use to run the encoding.
/// - doc: The document to create/overwrite the encoded data to.
/// - Returns: This instance of `Transaction`. Used for chaining method calls.
@discardableResult
func setData<T: Encodable>(from value: T,
forDocument doc: DocumentReference,
encoder: Firestore.Encoder = Firestore
.Encoder()) throws -> Transaction {
let encoded = try encoder.encode(value)
setData(encoded, forDocument: doc)
return self
}
/// Encodes an instance of `Encodable` and overwrites the encoded data
/// to the document referred by `doc`. If no document exists,
/// it is created. If a document already exists, it is overwritten. If you pass
/// merge:true, the provided `Encodable` will be merged into any existing document.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - doc: The document to create/overwrite the encoded data to.
/// - merge: Whether to merge the provided `Encodable` into any existing
/// document.
/// - encoder: The encoder instance to use to run the encoding.
/// - Returns: This instance of `Transaction`. Used for chaining method calls.
@discardableResult
func setData<T: Encodable>(from value: T,
forDocument doc: DocumentReference,
merge: Bool,
encoder: Firestore.Encoder = Firestore
.Encoder()) throws -> Transaction {
let encoded = try encoder.encode(value)
setData(encoded, forDocument: doc, merge: merge)
return self
}
/// Encodes an instance of `Encodable` and writes the encoded data to the document referred
/// by `doc` by only replacing the fields specified under `mergeFields`.
/// Any field that is not specified in mergeFields is ignored and remains untouched. If the
/// document doesnt yet exist, this method creates it and then sets the data.
///
/// It is an error to include a field in `mergeFields` that does not have a corresponding
/// field in the `Encodable`.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - doc: The document to create/overwrite the encoded data to.
/// - mergeFields: Array of `String` or `FieldPath` elements specifying which fields to
/// merge. Fields can contain dots to reference nested fields within the
/// document.
/// - encoder: The encoder instance to use to run the encoding.
/// - Returns: This instance of `Transaction`. Used for chaining method calls.
@discardableResult
func setData<T: Encodable>(from value: T,
forDocument doc: DocumentReference,
mergeFields: [Any],
encoder: Firestore.Encoder = Firestore
.Encoder()) throws -> Transaction {
let encoded = try encoder.encode(value)
setData(encoded, forDocument: doc, mergeFields: mergeFields)
return self
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright 2019 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.
*/
import Foundation
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
public extension WriteBatch {
/// Encodes an instance of `Encodable` and overwrites the encoded data
/// to the document referred by `doc`. If no document exists,
/// it is created. If a document already exists, it is overwritten.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - encoder: The encoder instance to use to run the encoding.
/// - doc: The document to create/overwrite the encoded data to.
/// - Returns: This instance of `WriteBatch`. Used for chaining method calls.
@discardableResult
func setData<T: Encodable>(from value: T,
forDocument doc: DocumentReference,
encoder: Firestore.Encoder = Firestore
.Encoder()) throws -> WriteBatch {
let encoded = try encoder.encode(value)
setData(encoded, forDocument: doc)
return self
}
/// Encodes an instance of `Encodable` and overwrites the encoded data
/// to the document referred by `doc`. If no document exists,
/// it is created. If a document already exists, it is overwritten. If you pass
/// merge:true, the provided `Encodable` will be merged into any existing document.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - doc: The document to create/overwrite the encoded data to.
/// - merge: Whether to merge the provided `Encodable` into any existing
/// document.
/// - encoder: The encoder instance to use to run the encoding.
/// - Returns: This instance of `WriteBatch`. Used for chaining method calls.
@discardableResult
func setData<T: Encodable>(from value: T,
forDocument doc: DocumentReference,
merge: Bool,
encoder: Firestore.Encoder = Firestore
.Encoder()) throws -> WriteBatch {
let encoded = try encoder.encode(value)
setData(encoded, forDocument: doc, merge: merge)
return self
}
/// Encodes an instance of `Encodable` and writes the encoded data to the document referred
/// by `doc` by only replacing the fields specified under `mergeFields`.
/// Any field that is not specified in mergeFields is ignored and remains untouched. If the
/// document doesnt yet exist, this method creates it and then sets the data.
///
/// It is an error to include a field in `mergeFields` that does not have a corresponding
/// field in the `Encodable`.
///
/// See `Firestore.Encoder` for more details about the encoding process.
///
/// - Parameters:
/// - value: An instance of `Encodable` to be encoded to a document.
/// - doc: The document to create/overwrite the encoded data to.
/// - mergeFields: Array of `String` or `FieldPath` elements specifying which fields to
/// merge. Fields can contain dots to reference nested fields within the
/// document.
/// - encoder: The encoder instance to use to run the encoding.
/// - Returns: This instance of `WriteBatch`. Used for chaining method calls.
@discardableResult
func setData<T: Encodable>(from value: T,
forDocument doc: DocumentReference,
mergeFields: [Any],
encoder: Firestore.Encoder = Firestore
.Encoder()) throws -> WriteBatch {
let encoded = try encoder.encode(value)
setData(encoded, forDocument: doc, mergeFields: mergeFields)
return self
}
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright 2021 Google LLC
*
* 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.
*/
import SwiftUI
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
/// The strategy to use when an error occurs during mapping Firestore documents
/// to the target type of `FirestoreQuery`.
///
public enum DecodingFailureStrategy {
/// Ignore any errors that occur when mapping Firestore documents.
case ignore
/// Raise an error when mapping a Firestore document fails.
case raise
}
/// A property wrapper that listens to a Firestore collection.
///
/// In the following example, `FirestoreQuery` will fetch all documents from the
/// `fruits` collection, filtering only documents whose `isFavourite` attribute
/// is equal to `true`, map members of result set to the `Fruit` type, and make
/// them available via the wrapped value `fruits`.
///
/// struct ContentView: View {
/// @FirestoreQuery(
/// collectionPath: "fruits",
/// predicates: [.whereField("isFavourite", isEqualTo: true)]
/// ) var fruits: [Fruit]
///
/// var body: some View {
/// List(fruits) { fruit in
/// Text(fruit.name)
/// }
/// }
/// }
///
/// `FirestoreQuery` also supports returning a `Result` type. The `.success` case
/// returns an array of elements, whereas the `.failure` case returns an error
/// in case mapping the Firestore docments wasn't successful:
///
/// struct ContentView: View {
/// @FirestoreQuery(
/// collectionPath: "fruits",
/// predicates: [.whereField("isFavourite", isEqualTo: true)]
/// ) var fruitResults: Result<[Fruit], Error>
///
/// var body: some View {
/// if case let .success(fruits) = fruitResults {
/// List(fruits) { fruit in
/// Text(fruit.name)
/// }
/// } else if case let .failure(error) = fruitResults {
/// Text("Couldn't map data: \(error.localizedDescription)")
/// }
/// }
///
/// Alternatively, the _projected value_ of the property wrapper provides access to
/// the `error` as well. This allows you to display a list of all successfully mapped
/// documents, as well as an error message with details about the documents that couldn't
/// be mapped successfully (e.g. because of a field name mismatch).
///
/// struct ContentView: View {
/// @FirestoreQuery(
/// collectionPath: "mappingFailure",
/// decodingFailureStrategy: .ignore
/// ) private var fruits: [Fruit]
///
/// var body: some View {
/// VStack(alignment: .leading) {
/// List(fruits) { fruit in
/// Text(fruit.name)
/// }
/// if $fruits.error != nil {
/// HStack {
/// Text("There was an error")
/// .foregroundColor(Color(UIColor.systemBackground))
/// Spacer()
/// }
/// .padding(30)
/// .background(Color.red)
/// }
/// }
/// }
/// }
///
/// Internally, `@FirestoreQuery` sets up a snapshot listener and publishes
/// any incoming changes via an `@StateObject`.
///
/// The projected value of this property wrapper provides access to a
/// configuration object of type `FirestoreQueryConfiguration` which can be used
/// to modify the query criteria. Changing the filter predicates results in the
/// underlying snapshot listener being unregistered and a new one registered.
///
/// Button("Show only Apples and Oranges") {
/// $fruits.predicates = [.whereField("name", isIn: ["Apple", "Orange]]
/// }
///
/// This property wrapper does not support updating the `wrappedValue`, i.e.
/// you need to use Firestore's other APIs to add, delete, or modify documents.
@available(iOS 14.0, macOS 11.0, macCatalyst 14.0, tvOS 14.0, watchOS 7.0, *)
@propertyWrapper
public struct FirestoreQuery<T>: DynamicProperty {
@StateObject private var firestoreQueryObservable: FirestoreQueryObservable<T>
/// The query's configurable properties.
public struct Configuration {
/// The query's collection path.
public var path: String
/// The query's predicates.
public var predicates: [QueryPredicate]
/// The strategy to use in case there was a problem during the decoding phase.
public var decodingFailureStrategy: DecodingFailureStrategy = .raise
/// If any errors occurred, they will be exposed here as well.
public var error: Error?
/// The type of animation to apply when updating the view. If this is ommitted then no
/// animations are fired.
public var animation: Animation?
}
/// The results of the query.
///
/// This property returns an empty collection when there are no matching results.
public var wrappedValue: T {
firestoreQueryObservable.items
}
/// A binding to the request's mutable configuration properties
public var projectedValue: Configuration {
get {
firestoreQueryObservable.configuration
}
nonmutating set {
firestoreQueryObservable.objectWillChange.send()
firestoreQueryObservable.configuration = newValue
}
}
/// Creates an instance by defining a query based on the parameters.
/// - Parameters:
/// - collectionPath: The path to the Firestore collection to query.
/// - predicates: An optional array of `QueryPredicate`s that defines a
/// filter for the fetched results.
/// - decodingFailureStrategy: The strategy to use when there is a failure
/// during the decoding phase. Defaults to `DecodingFailureStrategy.raise`.
/// - animation: The optional animation to apply to the transaction.
public init<U: Decodable>(collectionPath: String, predicates: [QueryPredicate] = [],
decodingFailureStrategy: DecodingFailureStrategy = .raise,
animation: Animation? = nil)
where T == [U] {
let configuration = Configuration(
path: collectionPath,
predicates: predicates,
decodingFailureStrategy: decodingFailureStrategy,
animation: animation
)
_firestoreQueryObservable =
StateObject(wrappedValue: FirestoreQueryObservable<T>(configuration: configuration))
}
/// Creates an instance by defining a query based on the parameters.
/// - Parameters:
/// - collectionPath: The path to the Firestore collection to query.
/// - predicates: An optional array of `QueryPredicate`s that defines a
/// filter for the fetched results.
/// - decodingFailureStrategy: The strategy to use when there is a failure
/// during the decoding phase. Defaults to `DecodingFailureStrategy.raise`.
/// - animation: The optional animation to apply to the transaction.
public init<U: Decodable>(collectionPath: String, predicates: [QueryPredicate] = [],
decodingFailureStrategy: DecodingFailureStrategy = .raise,
animation: Animation? = nil)
where T == Result<[U], Error> {
let configuration = Configuration(
path: collectionPath,
predicates: predicates,
decodingFailureStrategy: decodingFailureStrategy,
animation: animation
)
_firestoreQueryObservable =
StateObject(wrappedValue: FirestoreQueryObservable<T>(configuration: configuration))
}
}

View File

@@ -0,0 +1,221 @@
/*
* Copyright 2021 Google LLC
*
* 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.
*/
import SwiftUI
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
@available(iOS 14.0, macOS 11.0, macCatalyst 14.0, tvOS 14.0, watchOS 7.0, *)
class FirestoreQueryObservable<T>: ObservableObject {
@Published var items: T
private let firestore = Firestore.firestore()
private var listener: ListenerRegistration?
private var setupListener: (() -> Void)!
var shouldUpdateListener = true
var configuration: FirestoreQuery<T>.Configuration {
didSet {
// prevent never-ending update cycle when updating the error field
guard shouldUpdateListener else { return }
removeListener()
setupListener()
}
}
init<U: Decodable>(configuration: FirestoreQuery<T>.Configuration) where T == [U] {
items = []
self.configuration = configuration
setupListener = createListener { [weak self] querySnapshot, error in
guard let self = self else { return }
if let error = error {
self.animated {
self.items = []
self.projectError(error)
}
return
} else {
self.animated {
self.projectError(nil)
}
}
guard let documents = querySnapshot?.documents else {
self.animated {
self.items = []
}
return
}
let decodedDocuments: [U] = documents.compactMap { queryDocumentSnapshot in
let result = Result { try queryDocumentSnapshot.data(as: U.self) }
switch result {
case let .success(decodedDocument):
return decodedDocument
case let .failure(error):
self.animated {
self.projectError(error)
}
return nil
}
}
if configuration.error != nil {
if configuration.decodingFailureStrategy == .raise {
self.animated {
self.items = []
}
} else {
self.animated {
self.items = decodedDocuments
}
}
} else {
self.animated {
self.items = decodedDocuments
}
}
}
setupListener()
}
init<U: Decodable>(configuration: FirestoreQuery<T>.Configuration) where T == Result<[U], Error> {
items = .success([])
self.configuration = configuration
setupListener = createListener { [weak self] querySnapshot, error in
guard let self = self else { return }
if let error = error {
self.animated {
self.items = .failure(error)
self.projectError(error)
}
return
} else {
self.animated {
self.projectError(nil)
}
}
guard let documents = querySnapshot?.documents else {
self.animated {
self.items = .success([])
}
return
}
let decodedDocuments: [U] = documents.compactMap { queryDocumentSnapshot in
let result = Result { try queryDocumentSnapshot.data(as: U.self) }
switch result {
case let .success(decodedDocument):
return decodedDocument
case let .failure(error):
self.animated {
self.projectError(error)
}
return nil
}
}
if let error = self.configuration.error {
if configuration.decodingFailureStrategy == .raise {
self.animated {
self.items = .failure(error)
}
} else {
self.animated {
self.items = .success(decodedDocuments)
}
}
} else {
self.animated {
self.items = .success(decodedDocuments)
}
}
}
setupListener()
}
deinit {
removeListener()
}
private func createListener(with handler: @escaping (QuerySnapshot?, Error?) -> Void)
-> () -> Void {
return {
var query: Query = self.firestore.collection(self.configuration.path)
for predicate in self.configuration.predicates {
switch predicate {
case let .isEqualTo(field, value):
query = query.whereField(field, isEqualTo: value)
case let .isIn(field, values):
query = query.whereField(field, in: values)
case let .isNotIn(field, values):
query = query.whereField(field, notIn: values)
case let .arrayContains(field, value):
query = query.whereField(field, arrayContains: value)
case let .arrayContainsAny(field, values):
query = query.whereField(field, arrayContainsAny: values)
case let .isLessThan(field, value):
query = query.whereField(field, isLessThan: value)
case let .isGreaterThan(field, value):
query = query.whereField(field, isGreaterThan: value)
case let .isLessThanOrEqualTo(field, value):
query = query.whereField(field, isLessThanOrEqualTo: value)
case let .isGreaterThanOrEqualTo(field, value):
query = query.whereField(field, isGreaterThanOrEqualTo: value)
case let .orderBy(field, value):
query = query.order(by: field, descending: value)
case let .limitTo(field):
query = query.limit(to: field)
case let .limitToLast(field):
query = query.limit(toLast: field)
}
}
self.listener = query.addSnapshotListener(handler)
}
}
private func projectError(_ error: Error?) {
shouldUpdateListener = false
configuration.error = error
shouldUpdateListener = true
}
private func removeListener() {
listener?.remove()
listener = nil
}
private func animated(_ body: () -> Void) {
if let animation = configuration.animation {
withAnimation(animation) {
body()
}
} else {
body()
}
}
}

View File

@@ -0,0 +1,142 @@
/*
* Copyright 2021 Google LLC
*
* 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.
*/
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
/// Query predicates that can be used to filter results fetched by `FirestoreQuery`.
///
/// Construct predicates using one of the following ways:
///
/// let onlyFavourites: QueryPredicate = .whereField("isFavourite", isEqualTo: true)
/// let onlyFavourites2: QueryPredicate = .isEqualTo("isFavourite", true)
/// let onlyFavourites3: QueryPredicate = .where("isFavourite", isEqualTo: true)
public enum QueryPredicate {
case isEqualTo(_ field: String, _ value: Any)
case isIn(_ field: String, _ values: [Any])
case isNotIn(_ field: String, _ values: [Any])
case arrayContains(_ field: String, _ value: Any)
case arrayContainsAny(_ field: String, _ values: [Any])
case isLessThan(_ field: String, _ value: Any)
case isGreaterThan(_ field: String, _ value: Any)
case isLessThanOrEqualTo(_ field: String, _ value: Any)
case isGreaterThanOrEqualTo(_ field: String, _ value: Any)
case orderBy(_ field: String, _ value: Bool)
case limitTo(_ value: Int)
case limitToLast(_ value: Int)
/*
Factory methods
*/
public static func whereField(_ field: String, isEqualTo value: Any) -> QueryPredicate {
.isEqualTo(field, value)
}
public static func whereField(_ field: String, isIn values: [Any]) -> QueryPredicate {
.isIn(field, values)
}
public static func whereField(_ field: String, isNotIn values: [Any]) -> QueryPredicate {
.isNotIn(field, values)
}
public static func whereField(_ field: String, arrayContains value: Any) -> QueryPredicate {
.arrayContains(field, value)
}
public static func whereField(_ field: String,
arrayContainsAny values: [Any]) -> QueryPredicate {
.arrayContainsAny(field, values)
}
public static func whereField(_ field: String, isLessThan value: Any) -> QueryPredicate {
.isLessThan(field, value)
}
public static func whereField(_ field: String, isGreaterThan value: Any) -> QueryPredicate {
.isGreaterThan(field, value)
}
public static func whereField(_ field: String,
isLessThanOrEqualTo value: Any) -> QueryPredicate {
.isLessThanOrEqualTo(field, value)
}
public static func whereField(_ field: String,
isGreaterThanOrEqualTo value: Any) -> QueryPredicate {
.isGreaterThanOrEqualTo(field, value)
}
public static func order(by field: String, descending value: Bool = false) -> QueryPredicate {
.orderBy(field, value)
}
public static func limit(to value: Int) -> QueryPredicate {
.limitTo(value)
}
public static func limit(toLast value: Int) -> QueryPredicate {
.limitToLast(value)
}
// Alternate naming
public static func `where`(_ name: String, isEqualTo value: Any) -> QueryPredicate {
.isEqualTo(name, value)
}
public static func `where`(_ name: String, isIn values: [Any]) -> QueryPredicate {
.isIn(name, values)
}
public static func `where`(_ name: String, isNotIn values: [Any]) -> QueryPredicate {
.isNotIn(name, values)
}
public static func `where`(field name: String, arrayContains value: Any) -> QueryPredicate {
.arrayContains(name, value)
}
public static func `where`(_ name: String, arrayContainsAny values: [Any]) -> QueryPredicate {
.arrayContainsAny(name, values)
}
public static func `where`(_ name: String, isLessThan value: Any) -> QueryPredicate {
.isLessThan(name, value)
}
public static func `where`(_ name: String, isGreaterThan value: Any) -> QueryPredicate {
.isGreaterThan(name, value)
}
public static func `where`(_ name: String, isLessThanOrEqualTo value: Any) -> QueryPredicate {
.isLessThanOrEqualTo(name, value)
}
public static func `where`(_ name: String,
isGreaterThanOrEqualTo value: Any) -> QueryPredicate {
.isGreaterThanOrEqualTo(name, value)
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyTrackingDomains</key>
<array>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array>
<dict>
<key>NSPrivacyCollectedDataType</key>
<string>NSPrivacyCollectedDataTypeOtherDiagnosticData</string>
<key>NSPrivacyCollectedDataTypeLinked</key>
<false/>
<key>NSPrivacyCollectedDataTypeTracking</key>
<false/>
<key>NSPrivacyCollectedDataTypePurposes</key>
<array>
<string>NSPrivacyCollectedDataTypePurposeAnalytics</string>
</array>
</dict>
</array>
<key>NSPrivacyAccessedAPITypes</key>
<array>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,32 @@
// Copyright 2023 Google LLC
//
// 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.
#if SWIFT_PACKAGE
@_exported import FirebaseFirestoreInternalWrapper
#else
@_exported import FirebaseFirestoreInternal
#endif // SWIFT_PACKAGE
// This is a trick to force generate a `FirebaseFirestore-Swift.h`
// header that re-exports `FirebaseFirestoreInternal` for Objective-C
// clients. It is important for the below code to reference a Firestore
// symbol defined in Objective-C as that will import the symbol's
// module (`FirebaseFirestoreInternal`) in the generated header. This
// allows Objective-C clients to import Firestore's Objective-C API
// using `@import FirebaseFirestore;`. This API is not needed for Swift
// clients and is therefore unavailable in a Swift context.
@available(*, unavailable)
@objc public extension Firestore {
static var __no_op: () -> Void { {} }
}

297
Pods/FirebaseFirestore/README.md generated Normal file
View File

@@ -0,0 +1,297 @@
<p align="center">
<a href="https://cocoapods.org/pods/Firebase">
<img src="https://img.shields.io/github/v/release/Firebase/firebase-ios-sdk?style=flat&label=CocoaPods"/>
</a>
<a href="https://swiftpackageindex.com/firebase/firebase-ios-sdk">
<img src="https://img.shields.io/github/v/release/Firebase/firebase-ios-sdk?style=flat&label=Swift%20Package%20Index&color=red"/>
</a>
<a href="https://cocoapods.org/pods/Firebase">
<img src="https://img.shields.io/github/license/Firebase/firebase-ios-sdk?style=flat"/>
</a><br/>
<a href="https://swiftpackageindex.com/firebase/firebase-ios-sdk">
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ffirebase%2Ffirebase-ios-sdk%2Fbadge%3Ftype%3Dplatforms"/>
</a>
<a href="https://swiftpackageindex.com/firebase/firebase-ios-sdk">
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ffirebase%2Ffirebase-ios-sdk%2Fbadge%3Ftype%3Dswift-versions"/>
</a>
</p>
# Firebase Apple Open Source Development
This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics.
Firebase is an app development platform with tools to help you build, grow, and
monetize your app. More information about Firebase can be found on the
[official Firebase website](https://firebase.google.com).
## Installation
See the subsections below for details about the different installation methods. Where
available, it's recommended to install any libraries with a `Swift` suffix to get the
best experience when writing your app in Swift.
1. [Standard pod install](#standard-pod-install)
2. [Swift Package Manager](#swift-package-manager)
3. [Installing from the GitHub repo](#installing-from-github)
4. [Experimental Carthage](#carthage-ios-only)
### Standard pod install
For instructions on the standard pod install, visit:
[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup).
### Swift Package Manager
Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be
found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file.
### Installing from GitHub
These instructions can be used to access the Firebase repo at other branches,
tags, or commits.
#### Background
See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod)
for instructions and options about overriding pod source locations.
#### Accessing Firebase Source Snapshots
All official releases are tagged in this repo and available via CocoaPods. To access a local
source snapshot or unreleased branch, use Podfile directives like the following:
To access FirebaseFirestore via a branch:
```ruby
pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main'
pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main'
```
To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo:
```ruby
pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk'
pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk'
```
### Carthage (iOS only)
Instructions for the experimental Carthage distribution can be found at
[Carthage.md](Carthage.md).
### Using Firebase from a Framework or a library
For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md).
## Development
To develop Firebase software in this repository, ensure that you have at least
the following software:
* Xcode 14.1 (or later)
CocoaPods is still the canonical way to develop, but much of the repo now supports
development with Swift Package Manager.
### CocoaPods
Install the following:
* CocoaPods 1.12.0 (or later)
* [CocoaPods generate](https://github.com/square/cocoapods-generate)
For the pod that you want to develop:
```ruby
pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios
```
Note: If the CocoaPods cache is out of date, you may need to run
`pod repo update` before the `pod gen` command.
Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for
those platforms. Since 10.2, Xcode does not properly handle multi-platform
CocoaPods workspaces.
Firestore has a self-contained Xcode project. See
[Firestore/README](Firestore/README.md) Markdown file.
#### Development for Catalyst
* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios`
* Check the Mac box in the App-iOS Build Settings
* Sign the App in the Settings Signing & Capabilities tab
* Click Pods in the Project Manager
* Add Signing to the iOS host app and unit test targets
* Select the Unit-unit scheme
* Run it to build and test
Alternatively, disable signing in each target:
* Go to Build Settings tab
* Click `+`
* Select `Add User-Defined Setting`
* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO`
### Swift Package Manager
* To enable test schemes: `./scripts/setup_spm_tests.sh`
* `open Package.swift` or double click `Package.swift` in Finder.
* Xcode will open the project
* Choose a scheme for a library to build or test suite to run
* Choose a target platform by selecting the run destination along with the scheme
### Adding a New Firebase Pod
Refer to [AddNewPod](AddNewPod.md) Markdown file for details.
### Managing Headers and Imports
For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file.
### Code Formatting
To ensure that the code is formatted consistently, run the script
[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh)
before creating a pull request (PR).
GitHub Actions will verify that any code changes are done in a style-compliant
way. Install `clang-format` and `mint`:
```console
brew install clang-format@18
brew install mint
```
### Running Unit Tests
Select a scheme and press Command-u to build a component and run its unit tests.
### Running Sample Apps
To run the sample apps and integration tests, you'll need a valid
`GoogleService-Info.plist
` file. The Firebase Xcode project contains dummy plist
files without real values, but they can be replaced with real plist files. To get your own
`GoogleService-Info.plist` files:
1. Go to the [Firebase Console](https://console.firebase.google.com/)
2. Create a new Firebase project, if you don't already have one
3. For each sample app you want to test, create a new Firebase app with the sample app's bundle
identifier (e.g., `com.google.Database-Example`)
4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project.
### Coverage Report Generation
For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file.
## Specific Component Instructions
See the sections below for any special instructions for those components.
### Firebase Auth
For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about
building and running the FirebaseAuth pod along with various samples and tests.
### Firebase Database
The Firebase Database Integration tests can be run against a locally running Database Emulator
or against a production instance.
To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before
running the integration test.
To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to
`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to
[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are
running.
### Firebase Dynamic Links
Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025.
Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance.
### Firebase Performance Monitoring
For specific Firebase Performance Monitoring development, see
[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK
and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about
integrating Performance with the dev test App.
### Firebase Storage
To run the Storage Integration tests, follow the instructions in
[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift).
#### Push Notifications
Push notifications can only be delivered to specially provisioned App IDs in the developer portal.
In order to test receiving push notifications, you will need to:
1. Change the bundle identifier of the sample app to something you own in your Apple Developer
account and enable that App ID for push notifications.
2. You'll also need to
[upload your APNs Provider Authentication Key or certificate to the
Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs)
at **Project Settings > Cloud Messaging > [Your Firebase App]**.
3. Ensure your iOS device is added to your Apple Developer portal as a test device.
#### iOS Simulator
The iOS Simulator cannot register for remote notifications and will not receive push notifications.
To receive push notifications, follow the steps above and run the app on a physical device.
## Building with Firebase on Apple platforms
Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS
are community supported. Thanks to community contributions for many of the multi-platform PRs.
At this time, most of Firebase's products are available across Apple platforms. There are still
a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see
[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform)
in Firebase's documentation.
### visionOS
Where supported, visionOS works as expected with the exception of Firestore via Swift Package
Manager where it is required to use the source distribution.
To enable the Firestore source distribution, quit Xcode and open the desired
project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment
variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`.
To go back to using the binary distribution of Firestore, quit Xcode and open
Xcode like normal, without the environment variable.
### watchOS
Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and
work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample).
Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit
test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected
on watchOS. If you encounter this, please
[file an issue](https://github.com/firebase/firebase-ios-sdk/issues).
During app setup in the console, you may get to a step that mentions something like "Checking if the
app has communicated with our servers". This relies on Analytics and will not work on watchOS.
**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected.
#### Additional Crashlytics Notes
* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are
not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded)
## Combine
Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine
framework. This module is currently under development and not yet supported for use in production
environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md).
## Roadmap
See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source
plans and directions.
## Contributing
See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase
Apple SDK.
## License
The contents of this repository are licensed under the
[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
Your use of Firebase is governed by the
[Terms of Service for Firebase Services](https://firebase.google.com/terms/).